1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: GDI Driver Device Functions 5 * FILE: win32ss/gdi/eng/device.c 6 * PROGRAMER: Jason Filby 7 * Timo Kreuzer 8 */ 9 10 #include <win32k.h> 11 #include <ntddvdeo.h> 12 13 DBG_DEFAULT_CHANNEL(EngDev); 14 15 PGRAPHICS_DEVICE gpPrimaryGraphicsDevice; 16 PGRAPHICS_DEVICE gpVgaGraphicsDevice; 17 18 static PGRAPHICS_DEVICE gpGraphicsDeviceFirst = NULL; 19 static PGRAPHICS_DEVICE gpGraphicsDeviceLast = NULL; 20 static HSEMAPHORE ghsemGraphicsDeviceList; 21 static ULONG giDevNum = 1; 22 23 CODE_SEG("INIT") 24 NTSTATUS 25 NTAPI 26 InitDeviceImpl(VOID) 27 { 28 ghsemGraphicsDeviceList = EngCreateSemaphore(); 29 if (!ghsemGraphicsDeviceList) 30 return STATUS_INSUFFICIENT_RESOURCES; 31 32 return STATUS_SUCCESS; 33 } 34 35 static 36 BOOLEAN 37 EngpHasVgaDriver( 38 _In_ PGRAPHICS_DEVICE pGraphicsDevice) 39 { 40 WCHAR awcDeviceKey[256], awcServiceName[100]; 41 PWSTR lastBkSlash; 42 NTSTATUS Status; 43 ULONG cbValue; 44 HKEY hkey; 45 46 /* Open the key for the adapters */ 47 Status = RegOpenKey(L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO", &hkey); 48 if (!NT_SUCCESS(Status)) 49 { 50 ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key: 0x%08lx\n", Status); 51 return FALSE; 52 } 53 54 /* Read the name of the device key */ 55 cbValue = sizeof(awcDeviceKey); 56 Status = RegQueryValue(hkey, pGraphicsDevice->szNtDeviceName, REG_SZ, awcDeviceKey, &cbValue); 57 ZwClose(hkey); 58 if (!NT_SUCCESS(Status)) 59 { 60 ERR("Could not read '%S' registry value: 0x%08lx\n", Status); 61 return FALSE; 62 } 63 64 /* Replace 'DeviceN' by 'Video' */ 65 lastBkSlash = wcsrchr(awcDeviceKey, L'\\'); 66 if (!lastBkSlash) 67 { 68 ERR("Invalid registry key '%S'\n", lastBkSlash); 69 return FALSE; 70 } 71 if (!NT_SUCCESS(RtlStringCchCopyW(lastBkSlash + 1, 72 ARRAYSIZE(awcDeviceKey) - (lastBkSlash + 1 - awcDeviceKey), 73 L"Video"))) 74 { 75 ERR("Failed to add 'Video' to registry key '%S'\n", awcDeviceKey); 76 return FALSE; 77 } 78 79 /* Open device key */ 80 Status = RegOpenKey(awcDeviceKey, &hkey); 81 if (!NT_SUCCESS(Status)) 82 { 83 ERR("Could not open %S registry key: 0x%08lx\n", awcDeviceKey, Status); 84 return FALSE; 85 } 86 87 /* Read service name */ 88 cbValue = sizeof(awcServiceName); 89 Status = RegQueryValue(hkey, L"Service", REG_SZ, awcServiceName, &cbValue); 90 ZwClose(hkey); 91 if (!NT_SUCCESS(Status)) 92 { 93 ERR("Could not read Service registry value in %S: 0x%08lx\n", awcDeviceKey, Status); 94 return FALSE; 95 } 96 97 /* Device is using VGA driver if service name starts with 'VGA' (case insensitive) */ 98 return (_wcsnicmp(awcServiceName, L"VGA", 3) == 0); 99 } 100 101 /* 102 * Add a device to gpGraphicsDeviceFirst/gpGraphicsDeviceLast list (if not already present). 103 */ 104 _Requires_lock_held_(ghsemGraphicsDeviceList) 105 static 106 VOID 107 EngpLinkGraphicsDevice( 108 _In_ PGRAPHICS_DEVICE pToAdd) 109 { 110 PGRAPHICS_DEVICE pGraphicsDevice; 111 112 TRACE("EngLinkGraphicsDevice(%p)\n", pToAdd); 113 114 /* Search if device is not already linked */ 115 for (pGraphicsDevice = gpGraphicsDeviceFirst; 116 pGraphicsDevice; 117 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice) 118 { 119 if (pGraphicsDevice == pToAdd) 120 return; 121 } 122 123 pToAdd->pNextGraphicsDevice = NULL; 124 if (gpGraphicsDeviceLast) 125 gpGraphicsDeviceLast->pNextGraphicsDevice = pToAdd; 126 gpGraphicsDeviceLast = pToAdd; 127 if (!gpGraphicsDeviceFirst) 128 gpGraphicsDeviceFirst = pToAdd; 129 } 130 131 /* 132 * Remove a device from gpGraphicsDeviceFirst/gpGraphicsDeviceLast list. 133 */ 134 _Requires_lock_held_(ghsemGraphicsDeviceList) 135 static 136 VOID 137 EngpUnlinkGraphicsDevice( 138 _In_ PGRAPHICS_DEVICE pToDelete) 139 { 140 PGRAPHICS_DEVICE pPrevGraphicsDevice = NULL; 141 PGRAPHICS_DEVICE pGraphicsDevice = gpGraphicsDeviceFirst; 142 143 TRACE("EngpUnlinkGraphicsDevice('%S')\n", pToDelete->szNtDeviceName); 144 145 while (pGraphicsDevice) 146 { 147 if (pGraphicsDevice != pToDelete) 148 { 149 /* Keep current device */ 150 pPrevGraphicsDevice = pGraphicsDevice; 151 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice; 152 } 153 else 154 { 155 /* At first, link again associated VGA Device */ 156 if (pGraphicsDevice->pVgaDevice) 157 EngpLinkGraphicsDevice(pGraphicsDevice->pVgaDevice); 158 159 /* We need to remove current device */ 160 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice; 161 162 /* Unlink chain */ 163 if (!pPrevGraphicsDevice) 164 gpGraphicsDeviceFirst = pToDelete->pNextGraphicsDevice; 165 else 166 pPrevGraphicsDevice->pNextGraphicsDevice = pToDelete->pNextGraphicsDevice; 167 if (gpGraphicsDeviceLast == pToDelete) 168 gpGraphicsDeviceLast = pPrevGraphicsDevice; 169 } 170 } 171 } 172 173 NTSTATUS 174 EngpUpdateGraphicsDeviceList(VOID) 175 { 176 ULONG iDevNum, iVGACompatible = -1, ulMaxObjectNumber = 0; 177 WCHAR awcDeviceName[20], awcWinDeviceName[20]; 178 UNICODE_STRING ustrDeviceName; 179 WCHAR awcBuffer[256]; 180 NTSTATUS Status; 181 PGRAPHICS_DEVICE pGraphicsDevice; 182 BOOLEAN bFoundNewDevice = FALSE; 183 ULONG cbValue; 184 HKEY hkey; 185 186 /* Open the key for the adapters */ 187 Status = RegOpenKey(L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO", &hkey); 188 if (!NT_SUCCESS(Status)) 189 { 190 ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key:0x%lx\n", Status); 191 return Status; 192 } 193 194 /* Read the name of the VGA adapter */ 195 cbValue = sizeof(awcDeviceName); 196 Status = RegQueryValue(hkey, L"VgaCompatible", REG_SZ, awcDeviceName, &cbValue); 197 if (NT_SUCCESS(Status)) 198 { 199 iVGACompatible = _wtoi(&awcDeviceName[sizeof("\\Device\\Video")-1]); 200 ERR("VGA adapter = %lu\n", iVGACompatible); 201 } 202 203 /* Get the maximum mumber of adapters */ 204 if (!RegReadDWORD(hkey, L"MaxObjectNumber", &ulMaxObjectNumber)) 205 { 206 ERR("Could not read MaxObjectNumber, defaulting to 0.\n"); 207 } 208 209 TRACE("Found %lu devices\n", ulMaxObjectNumber + 1); 210 211 /* Loop through all adapters */ 212 for (iDevNum = 0; iDevNum <= ulMaxObjectNumber; iDevNum++) 213 { 214 /* Create the adapter's key name */ 215 swprintf(awcDeviceName, L"\\Device\\Video%lu", iDevNum); 216 217 /* Create the display device name */ 218 swprintf(awcWinDeviceName, L"\\\\.\\DISPLAY%lu", iDevNum + 1); 219 RtlInitUnicodeString(&ustrDeviceName, awcWinDeviceName); 220 221 /* Check if the device exists already */ 222 pGraphicsDevice = EngpFindGraphicsDevice(&ustrDeviceName, iDevNum); 223 if (pGraphicsDevice != NULL) 224 { 225 continue; 226 } 227 228 /* Read the reg key name */ 229 cbValue = sizeof(awcBuffer); 230 Status = RegQueryValue(hkey, awcDeviceName, REG_SZ, awcBuffer, &cbValue); 231 if (!NT_SUCCESS(Status)) 232 { 233 ERR("failed to query the registry path:0x%lx\n", Status); 234 continue; 235 } 236 237 /* Initialize the driver for this device */ 238 pGraphicsDevice = InitDisplayDriver(awcDeviceName, awcBuffer); 239 if (!pGraphicsDevice) continue; 240 241 /* Check if this is a VGA compatible adapter */ 242 if (pGraphicsDevice->StateFlags & DISPLAY_DEVICE_VGA_COMPATIBLE) 243 { 244 /* Save this as the VGA adapter */ 245 if (!gpVgaGraphicsDevice) 246 { 247 gpVgaGraphicsDevice = pGraphicsDevice; 248 TRACE("gpVgaGraphicsDevice = %p\n", gpVgaGraphicsDevice); 249 } 250 } 251 bFoundNewDevice = TRUE; 252 253 /* Set the first one as primary device */ 254 if (!gpPrimaryGraphicsDevice || EngpHasVgaDriver(gpPrimaryGraphicsDevice)) 255 { 256 gpPrimaryGraphicsDevice = pGraphicsDevice; 257 TRACE("gpPrimaryGraphicsDevice = %p\n", gpPrimaryGraphicsDevice); 258 } 259 } 260 261 /* Close the device map registry key */ 262 ZwClose(hkey); 263 264 /* Can we link VGA device to primary device? */ 265 if (gpPrimaryGraphicsDevice && 266 gpVgaGraphicsDevice && 267 gpPrimaryGraphicsDevice != gpVgaGraphicsDevice && 268 !gpPrimaryGraphicsDevice->pVgaDevice) 269 { 270 /* Yes. Remove VGA device from global list, and attach it to primary device */ 271 TRACE("Linking VGA device %S to primary device %S\n", gpVgaGraphicsDevice->szNtDeviceName, gpPrimaryGraphicsDevice->szNtDeviceName); 272 EngpUnlinkGraphicsDevice(gpVgaGraphicsDevice); 273 gpPrimaryGraphicsDevice->pVgaDevice = gpVgaGraphicsDevice; 274 } 275 276 if (bFoundNewDevice && gbBaseVideo) 277 { 278 PGRAPHICS_DEVICE pToDelete; 279 280 /* Lock list */ 281 EngAcquireSemaphore(ghsemGraphicsDeviceList); 282 283 /* Remove every device from linked list, except base-video one */ 284 pGraphicsDevice = gpGraphicsDeviceFirst; 285 while (pGraphicsDevice) 286 { 287 if (!EngpHasVgaDriver(pGraphicsDevice)) 288 { 289 /* Not base-video device. Remove it */ 290 pToDelete = pGraphicsDevice; 291 TRACE("Removing non-base-video device %S (%S)\n", pToDelete->szWinDeviceName, pToDelete->szNtDeviceName); 292 293 EngpUnlinkGraphicsDevice(pGraphicsDevice); 294 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice; 295 296 /* Free memory */ 297 ExFreePoolWithTag(pToDelete->pDiplayDrivers, GDITAG_DRVSUP); 298 ExFreePoolWithTag(pToDelete, GDITAG_GDEVICE); 299 } 300 else 301 { 302 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice; 303 } 304 } 305 306 /* Unlock list */ 307 EngReleaseSemaphore(ghsemGraphicsDeviceList); 308 } 309 310 return STATUS_SUCCESS; 311 } 312 313 /* Open display settings registry key 314 * Returns NULL in case of error. */ 315 static HKEY 316 EngpGetRegistryHandleFromDeviceMap( 317 _In_ PGRAPHICS_DEVICE pGraphicsDevice) 318 { 319 static const PWCHAR KEY_VIDEO = L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO"; 320 HKEY hKey; 321 WCHAR szDeviceKey[256]; 322 ULONG cbSize; 323 NTSTATUS Status; 324 325 /* Open the device map registry key */ 326 Status = RegOpenKey(KEY_VIDEO, &hKey); 327 if (!NT_SUCCESS(Status)) 328 { 329 ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key: status 0x%08x\n", Status); 330 return NULL; 331 } 332 333 /* Query the registry path */ 334 cbSize = sizeof(szDeviceKey); 335 RegQueryValue(hKey, 336 pGraphicsDevice->szNtDeviceName, 337 REG_SZ, 338 szDeviceKey, 339 &cbSize); 340 ZwClose(hKey); 341 342 /* Open the registry key */ 343 Status = RegOpenKey(szDeviceKey, &hKey); 344 if (!NT_SUCCESS(Status)) 345 { 346 ERR("Could not open registry key '%S': status 0x%08x\n", szDeviceKey, Status); 347 return NULL; 348 } 349 350 return hKey; 351 } 352 353 NTSTATUS 354 EngpGetDisplayDriverParameters( 355 _In_ PGRAPHICS_DEVICE pGraphicsDevice, 356 _Out_ PDEVMODEW pdm) 357 { 358 HKEY hKey; 359 NTSTATUS Status; 360 RTL_QUERY_REGISTRY_TABLE DisplaySettingsTable[] = 361 { 362 #define READ(field, str) \ 363 { \ 364 NULL, \ 365 RTL_QUERY_REGISTRY_DIRECT, \ 366 L ##str, \ 367 &pdm->field, \ 368 REG_NONE, NULL, 0 \ 369 }, 370 READ(dmBitsPerPel, "DefaultSettings.BitsPerPel") 371 READ(dmPelsWidth, "DefaultSettings.XResolution") 372 READ(dmPelsHeight, "DefaultSettings.YResolution") 373 READ(dmDisplayFlags, "DefaultSettings.Flags") 374 READ(dmDisplayFrequency, "DefaultSettings.VRefresh") 375 READ(dmPanningWidth, "DefaultSettings.XPanning") 376 READ(dmPanningHeight, "DefaultSettings.YPanning") 377 READ(dmDisplayOrientation, "DefaultSettings.Orientation") 378 READ(dmDisplayFixedOutput, "DefaultSettings.FixedOutput") 379 READ(dmPosition.x, "Attach.RelativeX") 380 READ(dmPosition.y, "Attach.RelativeY") 381 #undef READ 382 {0} 383 }; 384 385 hKey = EngpGetRegistryHandleFromDeviceMap(pGraphicsDevice); 386 if (!hKey) 387 return STATUS_UNSUCCESSFUL; 388 389 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 390 (PWSTR)hKey, 391 DisplaySettingsTable, 392 NULL, 393 NULL); 394 395 ZwClose(hKey); 396 return Status; 397 } 398 399 DWORD 400 EngpGetDisplayDriverAccelerationLevel( 401 _In_ PGRAPHICS_DEVICE pGraphicsDevice) 402 { 403 HKEY hKey; 404 DWORD dwAccelerationLevel = 0; 405 RTL_QUERY_REGISTRY_TABLE DisplaySettingsTable[] = 406 { 407 { 408 NULL, 409 RTL_QUERY_REGISTRY_DIRECT, 410 L"Acceleration.Level", 411 &dwAccelerationLevel, 412 REG_NONE, NULL, 0 413 }, 414 {0} 415 }; 416 417 hKey = EngpGetRegistryHandleFromDeviceMap(pGraphicsDevice); 418 if (!hKey) 419 return 0; 420 421 RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 422 (PWSTR)hKey, 423 DisplaySettingsTable, 424 NULL, 425 NULL); 426 ZwClose(hKey); 427 428 return dwAccelerationLevel; 429 } 430 431 extern VOID 432 UserRefreshDisplay(IN PPDEVOBJ ppdev); 433 434 // PVIDEO_WIN32K_CALLOUT 435 VOID 436 NTAPI 437 VideoPortCallout( 438 _In_ PVOID Params) 439 { 440 /* 441 * IMPORTANT NOTICE!! On Windows XP/2003 this function triggers the creation of 442 * a specific VideoPortCalloutThread() system thread using the same mechanism 443 * as the RIT/desktop/Ghost system threads. 444 */ 445 446 PVIDEO_WIN32K_CALLBACKS_PARAMS CallbackParams = (PVIDEO_WIN32K_CALLBACKS_PARAMS)Params; 447 448 TRACE("VideoPortCallout(0x%p, 0x%x)\n", 449 CallbackParams, CallbackParams ? CallbackParams->CalloutType : -1); 450 451 if (!CallbackParams) 452 return; 453 454 switch (CallbackParams->CalloutType) 455 { 456 case VideoFindAdapterCallout: 457 { 458 TRACE("VideoPortCallout: VideoFindAdapterCallout called - Param = %s\n", 459 CallbackParams->Param ? "TRUE" : "FALSE"); 460 if (CallbackParams->Param == TRUE) 461 { 462 /* Re-enable the display */ 463 UserRefreshDisplay(gpmdev->ppdevGlobal); 464 } 465 else 466 { 467 /* Disable the display */ 468 NOTHING; // Nothing to do for the moment... 469 } 470 471 CallbackParams->Status = STATUS_SUCCESS; 472 break; 473 } 474 475 case VideoPowerNotifyCallout: 476 case VideoDisplaySwitchCallout: 477 case VideoEnumChildPdoNotifyCallout: 478 case VideoWakeupCallout: 479 case VideoChangeDisplaySettingsCallout: 480 case VideoPnpNotifyCallout: 481 case VideoDxgkDisplaySwitchCallout: 482 case VideoDxgkMonitorEventCallout: 483 case VideoDxgkFindAdapterTdrCallout: 484 ERR("VideoPortCallout: CalloutType 0x%x is UNIMPLEMENTED!\n", CallbackParams->CalloutType); 485 CallbackParams->Status = STATUS_NOT_IMPLEMENTED; 486 break; 487 488 default: 489 ERR("VideoPortCallout: Unknown CalloutType 0x%x\n", CallbackParams->CalloutType); 490 CallbackParams->Status = STATUS_UNSUCCESSFUL; 491 break; 492 } 493 } 494 495 PGRAPHICS_DEVICE 496 NTAPI 497 EngpRegisterGraphicsDevice( 498 _In_ PUNICODE_STRING pustrDeviceName, 499 _In_ PUNICODE_STRING pustrDiplayDrivers, 500 _In_ PUNICODE_STRING pustrDescription) 501 { 502 PGRAPHICS_DEVICE pGraphicsDevice; 503 PDEVICE_OBJECT pDeviceObject; 504 PFILE_OBJECT pFileObject; 505 NTSTATUS Status; 506 VIDEO_WIN32K_CALLBACKS Win32kCallbacks; 507 ULONG ulReturn; 508 PWSTR pwsz; 509 ULONG cj; 510 511 TRACE("EngpRegisterGraphicsDevice(%wZ)\n", pustrDeviceName); 512 513 /* Allocate a GRAPHICS_DEVICE structure */ 514 pGraphicsDevice = ExAllocatePoolZero(PagedPool, 515 sizeof(GRAPHICS_DEVICE), 516 GDITAG_GDEVICE); 517 if (!pGraphicsDevice) 518 { 519 ERR("ExAllocatePoolWithTag failed\n"); 520 return NULL; 521 } 522 523 /* Try to open and enable the device */ 524 Status = IoGetDeviceObjectPointer(pustrDeviceName, 525 FILE_READ_DATA | FILE_WRITE_DATA, 526 &pFileObject, 527 &pDeviceObject); 528 if (!NT_SUCCESS(Status)) 529 { 530 ERR("Could not open device %wZ, 0x%lx\n", pustrDeviceName, Status); 531 ExFreePoolWithTag(pGraphicsDevice, GDITAG_GDEVICE); 532 return NULL; 533 } 534 535 /* Copy the device and file object pointers */ 536 pGraphicsDevice->DeviceObject = pDeviceObject; 537 pGraphicsDevice->FileObject = pFileObject; 538 539 /* Initialize and register the device with videoprt for Win32k callbacks */ 540 Win32kCallbacks.PhysDisp = pGraphicsDevice; 541 Win32kCallbacks.Callout = VideoPortCallout; 542 // Reset the data being returned prior to the call. 543 Win32kCallbacks.bACPI = FALSE; 544 Win32kCallbacks.pPhysDeviceObject = NULL; 545 Win32kCallbacks.DualviewFlags = 0; 546 Status = (NTSTATUS)EngDeviceIoControl((HANDLE)pDeviceObject, 547 IOCTL_VIDEO_INIT_WIN32K_CALLBACKS, 548 &Win32kCallbacks, 549 sizeof(Win32kCallbacks), 550 &Win32kCallbacks, 551 sizeof(Win32kCallbacks), 552 &ulReturn); 553 if (Status != ERROR_SUCCESS) 554 { 555 ERR("EngDeviceIoControl(0x%p, IOCTL_VIDEO_INIT_WIN32K_CALLBACKS) failed, Status 0x%lx\n", 556 pDeviceObject, Status); 557 } 558 // TODO: Set flags according to the results. 559 // if (Win32kCallbacks.bACPI) 560 // if (Win32kCallbacks.DualviewFlags & ???) 561 pGraphicsDevice->PhysDeviceHandle = Win32kCallbacks.pPhysDeviceObject; 562 563 /* FIXME: Enumerate children monitor devices for this video adapter 564 * 565 * - Force the adapter to re-enumerate its monitors: 566 * IoSynchronousInvalidateDeviceRelations(pdo, BusRelations) 567 * 568 * - Retrieve all monitor PDOs from VideoPrt: 569 * EngDeviceIoControl(0x%p, IOCTL_VIDEO_ENUM_MONITOR_PDO) 570 * 571 * - Initialize these fields and structures accordingly: 572 * pGraphicsDevice->dwMonCnt 573 * pGraphicsDevice->pvMonDev[0..dwMonCnt-1] 574 */ 575 576 /* Copy the device name */ 577 RtlStringCbCopyNW(pGraphicsDevice->szNtDeviceName, 578 sizeof(pGraphicsDevice->szNtDeviceName), 579 pustrDeviceName->Buffer, 580 pustrDeviceName->Length); 581 582 /* Create a Win32 device name (FIXME: virtual devices!) */ 583 RtlStringCbPrintfW(pGraphicsDevice->szWinDeviceName, 584 sizeof(pGraphicsDevice->szWinDeviceName), 585 L"\\\\.\\DISPLAY%d", 586 (int)giDevNum); 587 588 /* Allocate a buffer for the strings */ 589 cj = pustrDiplayDrivers->Length + pustrDescription->Length + sizeof(WCHAR); 590 pwsz = ExAllocatePoolWithTag(PagedPool, cj, GDITAG_DRVSUP); 591 if (!pwsz) 592 { 593 ERR("Could not allocate string buffer\n"); 594 ASSERT(FALSE); // FIXME 595 ExFreePoolWithTag(pGraphicsDevice, GDITAG_GDEVICE); 596 return NULL; 597 } 598 599 /* Copy the display driver names */ 600 pGraphicsDevice->pDiplayDrivers = pwsz; 601 RtlCopyMemory(pGraphicsDevice->pDiplayDrivers, 602 pustrDiplayDrivers->Buffer, 603 pustrDiplayDrivers->Length); 604 605 /* Copy the description */ 606 pGraphicsDevice->pwszDescription = pwsz + pustrDiplayDrivers->Length / sizeof(WCHAR); 607 RtlCopyMemory(pGraphicsDevice->pwszDescription, 608 pustrDescription->Buffer, 609 pustrDescription->Length); 610 pGraphicsDevice->pwszDescription[pustrDescription->Length/sizeof(WCHAR)] = 0; 611 612 /* Lock loader */ 613 EngAcquireSemaphore(ghsemGraphicsDeviceList); 614 615 /* Insert the device into the global list */ 616 EngpLinkGraphicsDevice(pGraphicsDevice); 617 618 /* Increment the device number */ 619 giDevNum++; 620 621 /* Unlock loader */ 622 EngReleaseSemaphore(ghsemGraphicsDeviceList); 623 TRACE("Prepared %lu modes for %ls\n", pGraphicsDevice->cDevModes, pGraphicsDevice->pwszDescription); 624 625 /* HACK: already in graphic mode; display wallpaper on this new display */ 626 if (ScreenDeviceContext) 627 { 628 UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY"); 629 UNICODE_STRING DisplayName; 630 HDC hdc; 631 RtlInitUnicodeString(&DisplayName, pGraphicsDevice->szWinDeviceName); 632 hdc = IntGdiCreateDC(&DriverName, &DisplayName, NULL, NULL, FALSE); 633 IntPaintDesktop(hdc); 634 } 635 636 return pGraphicsDevice; 637 } 638 639 PGRAPHICS_DEVICE 640 NTAPI 641 EngpFindGraphicsDevice( 642 _In_opt_ PUNICODE_STRING pustrDevice, 643 _In_ ULONG iDevNum) 644 { 645 UNICODE_STRING ustrCurrent; 646 PGRAPHICS_DEVICE pGraphicsDevice; 647 ULONG i; 648 TRACE("EngpFindGraphicsDevice('%wZ', %lu)\n", 649 pustrDevice, iDevNum); 650 651 /* Lock list */ 652 EngAcquireSemaphore(ghsemGraphicsDeviceList); 653 654 if (pustrDevice && pustrDevice->Buffer) 655 { 656 /* Find specified video adapter by name */ 657 for (pGraphicsDevice = gpGraphicsDeviceFirst; 658 pGraphicsDevice; 659 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice) 660 { 661 /* Compare the device name */ 662 RtlInitUnicodeString(&ustrCurrent, pGraphicsDevice->szWinDeviceName); 663 if (RtlEqualUnicodeString(&ustrCurrent, pustrDevice, FALSE)) 664 { 665 break; 666 } 667 } 668 669 if (pGraphicsDevice) 670 { 671 /* Validate selected monitor number */ 672 #if 0 673 if (iDevNum >= pGraphicsDevice->dwMonCnt) 674 pGraphicsDevice = NULL; 675 #else 676 /* FIXME: dwMonCnt not initialized, see EngpRegisterGraphicsDevice */ 677 #endif 678 } 679 } 680 else 681 { 682 /* Select video adapter by device number */ 683 for (pGraphicsDevice = gpGraphicsDeviceFirst, i = 0; 684 pGraphicsDevice && i < iDevNum; 685 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice, i++); 686 } 687 688 /* Unlock list */ 689 EngReleaseSemaphore(ghsemGraphicsDeviceList); 690 691 return pGraphicsDevice; 692 } 693 694 static 695 NTSTATUS 696 EngpFileIoRequest( 697 _In_ PFILE_OBJECT pFileObject, 698 _In_ ULONG ulMajorFunction, 699 _In_reads_(nBufferSize) PVOID lpBuffer, 700 _In_ SIZE_T nBufferSize, 701 _In_ ULONGLONG ullStartOffset, 702 _Out_ PULONG_PTR lpInformation) 703 { 704 PDEVICE_OBJECT pDeviceObject; 705 KEVENT Event; 706 PIRP pIrp; 707 IO_STATUS_BLOCK Iosb; 708 NTSTATUS Status; 709 LARGE_INTEGER liStartOffset; 710 711 /* Get corresponding device object */ 712 pDeviceObject = IoGetRelatedDeviceObject(pFileObject); 713 if (!pDeviceObject) 714 { 715 return STATUS_INVALID_PARAMETER; 716 } 717 718 /* Initialize an event */ 719 KeInitializeEvent(&Event, SynchronizationEvent, FALSE); 720 721 /* Build IRP */ 722 liStartOffset.QuadPart = ullStartOffset; 723 pIrp = IoBuildSynchronousFsdRequest(ulMajorFunction, 724 pDeviceObject, 725 lpBuffer, 726 (ULONG)nBufferSize, 727 &liStartOffset, 728 &Event, 729 &Iosb); 730 if (!pIrp) 731 { 732 return STATUS_INSUFFICIENT_RESOURCES; 733 } 734 735 /* Call the driver */ 736 Status = IoCallDriver(pDeviceObject, pIrp); 737 738 /* Wait if neccessary */ 739 if (STATUS_PENDING == Status) 740 { 741 KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0); 742 Status = Iosb.Status; 743 } 744 745 /* Return information to the caller about the operation. */ 746 *lpInformation = Iosb.Information; 747 748 /* Return NTSTATUS */ 749 return Status; 750 } 751 752 VOID 753 APIENTRY 754 EngFileWrite( 755 _In_ PFILE_OBJECT pFileObject, 756 _In_reads_(nLength) PVOID lpBuffer, 757 _In_ SIZE_T nLength, 758 _Out_ PSIZE_T lpBytesWritten) 759 { 760 NTSTATUS status; 761 762 status = EngpFileIoRequest(pFileObject, 763 IRP_MJ_WRITE, 764 lpBuffer, 765 nLength, 766 0, 767 lpBytesWritten); 768 if (!NT_SUCCESS(status)) 769 { 770 *lpBytesWritten = 0; 771 } 772 } 773 774 _Success_(return>=0) 775 NTSTATUS 776 APIENTRY 777 EngFileIoControl( 778 _In_ PFILE_OBJECT pFileObject, 779 _In_ DWORD dwIoControlCode, 780 _In_reads_(nInBufferSize) PVOID lpInBuffer, 781 _In_ SIZE_T nInBufferSize, 782 _Out_writes_(nOutBufferSize) PVOID lpOutBuffer, 783 _In_ SIZE_T nOutBufferSize, 784 _Out_ PULONG_PTR lpInformation) 785 { 786 PDEVICE_OBJECT pDeviceObject; 787 KEVENT Event; 788 PIRP pIrp; 789 IO_STATUS_BLOCK Iosb; 790 NTSTATUS Status; 791 792 /* Get corresponding device object */ 793 pDeviceObject = IoGetRelatedDeviceObject(pFileObject); 794 if (!pDeviceObject) 795 { 796 return STATUS_INVALID_PARAMETER; 797 } 798 799 /* Initialize an event */ 800 KeInitializeEvent(&Event, SynchronizationEvent, FALSE); 801 802 /* Build IO control IRP */ 803 pIrp = IoBuildDeviceIoControlRequest(dwIoControlCode, 804 pDeviceObject, 805 lpInBuffer, 806 (ULONG)nInBufferSize, 807 lpOutBuffer, 808 (ULONG)nOutBufferSize, 809 FALSE, 810 &Event, 811 &Iosb); 812 if (!pIrp) 813 { 814 return STATUS_INSUFFICIENT_RESOURCES; 815 } 816 817 /* Call the driver */ 818 Status = IoCallDriver(pDeviceObject, pIrp); 819 820 /* Wait if neccessary */ 821 if (Status == STATUS_PENDING) 822 { 823 KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0); 824 Status = Iosb.Status; 825 } 826 827 /* Return information to the caller about the operation. */ 828 *lpInformation = Iosb.Information; 829 830 /* This function returns NTSTATUS */ 831 return Status; 832 } 833 834 /* 835 * @implemented 836 */ 837 _Success_(return==0) 838 DWORD 839 APIENTRY 840 EngDeviceIoControl( 841 _In_ HANDLE hDevice, 842 _In_ DWORD dwIoControlCode, 843 _In_reads_bytes_opt_(cjInBufferSize) LPVOID lpInBuffer, 844 _In_ DWORD cjInBufferSize, 845 _Out_writes_bytes_opt_(cjOutBufferSize) LPVOID lpOutBuffer, 846 _In_ DWORD cjOutBufferSize, 847 _Out_ LPDWORD lpBytesReturned) 848 { 849 PIRP Irp; 850 NTSTATUS Status; 851 KEVENT Event; 852 IO_STATUS_BLOCK Iosb; 853 PDEVICE_OBJECT DeviceObject; 854 855 TRACE("EngDeviceIoControl() called\n"); 856 857 if (!hDevice) 858 { 859 return ERROR_INVALID_HANDLE; 860 } 861 862 KeInitializeEvent(&Event, SynchronizationEvent, FALSE); 863 864 DeviceObject = (PDEVICE_OBJECT) hDevice; 865 866 Irp = IoBuildDeviceIoControlRequest(dwIoControlCode, 867 DeviceObject, 868 lpInBuffer, 869 cjInBufferSize, 870 lpOutBuffer, 871 cjOutBufferSize, 872 FALSE, 873 &Event, 874 &Iosb); 875 if (!Irp) return ERROR_NOT_ENOUGH_MEMORY; 876 877 Status = IoCallDriver(DeviceObject, Irp); 878 879 if (Status == STATUS_PENDING) 880 { 881 (VOID)KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0); 882 Status = Iosb.Status; 883 } 884 885 TRACE("EngDeviceIoControl(): Returning %X/%X\n", Iosb.Status, 886 Iosb.Information); 887 888 /* Return information to the caller about the operation. */ 889 *lpBytesReturned = (DWORD)Iosb.Information; 890 891 /* Convert NT status values to win32 error codes. */ 892 switch (Status) 893 { 894 case STATUS_INSUFFICIENT_RESOURCES: 895 return ERROR_NOT_ENOUGH_MEMORY; 896 897 case STATUS_BUFFER_OVERFLOW: 898 return ERROR_MORE_DATA; 899 900 case STATUS_NOT_IMPLEMENTED: 901 return ERROR_INVALID_FUNCTION; 902 903 case STATUS_INVALID_PARAMETER: 904 return ERROR_INVALID_PARAMETER; 905 906 case STATUS_BUFFER_TOO_SMALL: 907 return ERROR_INSUFFICIENT_BUFFER; 908 909 case STATUS_DEVICE_DOES_NOT_EXIST: 910 return ERROR_DEV_NOT_EXIST; 911 912 case STATUS_PENDING: 913 return ERROR_IO_PENDING; 914 } 915 916 return Status; 917 } 918 919 /* EOF */ 920