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 NTSTATUS 36 EngpUpdateGraphicsDeviceList(VOID) 37 { 38 ULONG iDevNum, iVGACompatible = -1, ulMaxObjectNumber = 0; 39 WCHAR awcDeviceName[20], awcWinDeviceName[20]; 40 UNICODE_STRING ustrDeviceName; 41 WCHAR awcBuffer[256]; 42 NTSTATUS Status; 43 PGRAPHICS_DEVICE pGraphicsDevice; 44 ULONG cbValue; 45 HKEY hkey; 46 47 /* Open the key for the adapters */ 48 Status = RegOpenKey(L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO", &hkey); 49 if (!NT_SUCCESS(Status)) 50 { 51 ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key:0x%lx\n", Status); 52 return Status; 53 } 54 55 /* Read the name of the VGA adapter */ 56 cbValue = sizeof(awcDeviceName); 57 Status = RegQueryValue(hkey, L"VgaCompatible", REG_SZ, awcDeviceName, &cbValue); 58 if (NT_SUCCESS(Status)) 59 { 60 iVGACompatible = _wtoi(&awcDeviceName[sizeof("\\Device\\Video")-1]); 61 ERR("VGA adapter = %lu\n", iVGACompatible); 62 } 63 64 /* Get the maximum mumber of adapters */ 65 if (!RegReadDWORD(hkey, L"MaxObjectNumber", &ulMaxObjectNumber)) 66 { 67 ERR("Could not read MaxObjectNumber, defaulting to 0.\n"); 68 } 69 70 TRACE("Found %lu devices\n", ulMaxObjectNumber + 1); 71 72 /* Loop through all adapters */ 73 for (iDevNum = 0; iDevNum <= ulMaxObjectNumber; iDevNum++) 74 { 75 /* Create the adapter's key name */ 76 swprintf(awcDeviceName, L"\\Device\\Video%lu", iDevNum); 77 78 /* Create the display device name */ 79 swprintf(awcWinDeviceName, L"\\\\.\\DISPLAY%lu", iDevNum + 1); 80 RtlInitUnicodeString(&ustrDeviceName, awcWinDeviceName); 81 82 /* Check if the device exists already */ 83 pGraphicsDevice = EngpFindGraphicsDevice(&ustrDeviceName, iDevNum); 84 if (pGraphicsDevice != NULL) 85 { 86 continue; 87 } 88 89 /* Read the reg key name */ 90 cbValue = sizeof(awcBuffer); 91 Status = RegQueryValue(hkey, awcDeviceName, REG_SZ, awcBuffer, &cbValue); 92 if (!NT_SUCCESS(Status)) 93 { 94 ERR("failed to query the registry path:0x%lx\n", Status); 95 continue; 96 } 97 98 /* Initialize the driver for this device */ 99 pGraphicsDevice = InitDisplayDriver(awcDeviceName, awcBuffer); 100 if (!pGraphicsDevice) continue; 101 102 /* Check if this is a VGA compatible adapter */ 103 if (pGraphicsDevice->StateFlags & DISPLAY_DEVICE_VGA_COMPATIBLE) 104 { 105 /* Save this as the VGA adapter */ 106 if (!gpVgaGraphicsDevice) 107 { 108 gpVgaGraphicsDevice = pGraphicsDevice; 109 TRACE("gpVgaGraphicsDevice = %p\n", gpVgaGraphicsDevice); 110 } 111 } 112 113 /* Set the first one as primary device */ 114 if (!gpPrimaryGraphicsDevice) 115 { 116 gpPrimaryGraphicsDevice = pGraphicsDevice; 117 TRACE("gpPrimaryGraphicsDevice = %p\n", gpPrimaryGraphicsDevice); 118 } 119 } 120 121 /* Close the device map registry key */ 122 ZwClose(hkey); 123 124 return STATUS_SUCCESS; 125 } 126 127 /* Open display settings registry key 128 * Returns NULL in case of error. */ 129 static HKEY 130 EngpGetRegistryHandleFromDeviceMap( 131 _In_ PGRAPHICS_DEVICE pGraphicsDevice) 132 { 133 static const PWCHAR KEY_VIDEO = L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO"; 134 HKEY hKey; 135 WCHAR szDeviceKey[256]; 136 ULONG cbSize; 137 NTSTATUS Status; 138 139 /* Open the device map registry key */ 140 Status = RegOpenKey(KEY_VIDEO, &hKey); 141 if (!NT_SUCCESS(Status)) 142 { 143 ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key: status 0x%08x\n", Status); 144 return NULL; 145 } 146 147 /* Query the registry path */ 148 cbSize = sizeof(szDeviceKey); 149 RegQueryValue(hKey, 150 pGraphicsDevice->szNtDeviceName, 151 REG_SZ, 152 szDeviceKey, 153 &cbSize); 154 ZwClose(hKey); 155 156 /* Open the registry key */ 157 Status = RegOpenKey(szDeviceKey, &hKey); 158 if (!NT_SUCCESS(Status)) 159 { 160 ERR("Could not open registry key '%S': status 0x%08x\n", szDeviceKey, Status); 161 return NULL; 162 } 163 164 return hKey; 165 } 166 167 NTSTATUS 168 EngpGetDisplayDriverParameters( 169 _In_ PGRAPHICS_DEVICE pGraphicsDevice, 170 _Out_ PDEVMODEW pdm) 171 { 172 HKEY hKey; 173 NTSTATUS Status; 174 RTL_QUERY_REGISTRY_TABLE DisplaySettingsTable[] = 175 { 176 #define READ(field, str) \ 177 { \ 178 NULL, \ 179 RTL_QUERY_REGISTRY_DIRECT, \ 180 L ##str, \ 181 &pdm->field, \ 182 REG_NONE, NULL, 0 \ 183 }, 184 READ(dmBitsPerPel, "DefaultSettings.BitsPerPel") 185 READ(dmPelsWidth, "DefaultSettings.XResolution") 186 READ(dmPelsHeight, "DefaultSettings.YResolution") 187 READ(dmDisplayFlags, "DefaultSettings.Flags") 188 READ(dmDisplayFrequency, "DefaultSettings.VRefresh") 189 READ(dmPanningWidth, "DefaultSettings.XPanning") 190 READ(dmPanningHeight, "DefaultSettings.YPanning") 191 READ(dmDisplayOrientation, "DefaultSettings.Orientation") 192 READ(dmDisplayFixedOutput, "DefaultSettings.FixedOutput") 193 READ(dmPosition.x, "Attach.RelativeX") 194 READ(dmPosition.y, "Attach.RelativeY") 195 #undef READ 196 {0} 197 }; 198 199 hKey = EngpGetRegistryHandleFromDeviceMap(pGraphicsDevice); 200 if (!hKey) 201 return STATUS_UNSUCCESSFUL; 202 203 Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 204 (PWSTR)hKey, 205 DisplaySettingsTable, 206 NULL, 207 NULL); 208 209 ZwClose(hKey); 210 return Status; 211 } 212 213 DWORD 214 EngpGetDisplayDriverAccelerationLevel( 215 _In_ PGRAPHICS_DEVICE pGraphicsDevice) 216 { 217 HKEY hKey; 218 DWORD dwAccelerationLevel = 0; 219 RTL_QUERY_REGISTRY_TABLE DisplaySettingsTable[] = 220 { 221 { 222 NULL, 223 RTL_QUERY_REGISTRY_DIRECT, 224 L"Acceleration.Level", 225 &dwAccelerationLevel, 226 REG_NONE, NULL, 0 227 }, 228 {0} 229 }; 230 231 hKey = EngpGetRegistryHandleFromDeviceMap(pGraphicsDevice); 232 if (!hKey) 233 return 0; 234 235 RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 236 (PWSTR)hKey, 237 DisplaySettingsTable, 238 NULL, 239 NULL); 240 ZwClose(hKey); 241 242 return dwAccelerationLevel; 243 } 244 245 extern VOID 246 UserRefreshDisplay(IN PPDEVOBJ ppdev); 247 248 // PVIDEO_WIN32K_CALLOUT 249 VOID 250 NTAPI 251 VideoPortCallout( 252 _In_ PVOID Params) 253 { 254 /* 255 * IMPORTANT NOTICE!! On Windows XP/2003 this function triggers the creation of 256 * a specific VideoPortCalloutThread() system thread using the same mechanism 257 * as the RIT/desktop/Ghost system threads. 258 */ 259 260 PVIDEO_WIN32K_CALLBACKS_PARAMS CallbackParams = (PVIDEO_WIN32K_CALLBACKS_PARAMS)Params; 261 262 TRACE("VideoPortCallout(0x%p, 0x%x)\n", 263 CallbackParams, CallbackParams ? CallbackParams->CalloutType : -1); 264 265 if (!CallbackParams) 266 return; 267 268 switch (CallbackParams->CalloutType) 269 { 270 case VideoFindAdapterCallout: 271 { 272 TRACE("VideoPortCallout: VideoFindAdapterCallout called - Param = %s\n", 273 CallbackParams->Param ? "TRUE" : "FALSE"); 274 if (CallbackParams->Param == TRUE) 275 { 276 /* Re-enable the display */ 277 UserRefreshDisplay(gpmdev->ppdevGlobal); 278 } 279 else 280 { 281 /* Disable the display */ 282 NOTHING; // Nothing to do for the moment... 283 } 284 285 CallbackParams->Status = STATUS_SUCCESS; 286 break; 287 } 288 289 case VideoPowerNotifyCallout: 290 case VideoDisplaySwitchCallout: 291 case VideoEnumChildPdoNotifyCallout: 292 case VideoWakeupCallout: 293 case VideoChangeDisplaySettingsCallout: 294 case VideoPnpNotifyCallout: 295 case VideoDxgkDisplaySwitchCallout: 296 case VideoDxgkMonitorEventCallout: 297 case VideoDxgkFindAdapterTdrCallout: 298 ERR("VideoPortCallout: CalloutType 0x%x is UNIMPLEMENTED!\n", CallbackParams->CalloutType); 299 CallbackParams->Status = STATUS_NOT_IMPLEMENTED; 300 break; 301 302 default: 303 ERR("VideoPortCallout: Unknown CalloutType 0x%x\n", CallbackParams->CalloutType); 304 CallbackParams->Status = STATUS_UNSUCCESSFUL; 305 break; 306 } 307 } 308 309 PGRAPHICS_DEVICE 310 NTAPI 311 EngpRegisterGraphicsDevice( 312 _In_ PUNICODE_STRING pustrDeviceName, 313 _In_ PUNICODE_STRING pustrDiplayDrivers, 314 _In_ PUNICODE_STRING pustrDescription) 315 { 316 PGRAPHICS_DEVICE pGraphicsDevice; 317 PDEVICE_OBJECT pDeviceObject; 318 PFILE_OBJECT pFileObject; 319 NTSTATUS Status; 320 VIDEO_WIN32K_CALLBACKS Win32kCallbacks; 321 ULONG ulReturn; 322 PWSTR pwsz; 323 ULONG cj; 324 325 TRACE("EngpRegisterGraphicsDevice(%wZ)\n", pustrDeviceName); 326 327 /* Allocate a GRAPHICS_DEVICE structure */ 328 pGraphicsDevice = ExAllocatePoolWithTag(PagedPool, 329 sizeof(GRAPHICS_DEVICE), 330 GDITAG_GDEVICE); 331 if (!pGraphicsDevice) 332 { 333 ERR("ExAllocatePoolWithTag failed\n"); 334 return NULL; 335 } 336 337 /* Try to open and enable the device */ 338 Status = IoGetDeviceObjectPointer(pustrDeviceName, 339 FILE_READ_DATA | FILE_WRITE_DATA, 340 &pFileObject, 341 &pDeviceObject); 342 if (!NT_SUCCESS(Status)) 343 { 344 ERR("Could not open device %wZ, 0x%lx\n", pustrDeviceName, Status); 345 ExFreePoolWithTag(pGraphicsDevice, GDITAG_GDEVICE); 346 return NULL; 347 } 348 349 /* Copy the device and file object pointers */ 350 pGraphicsDevice->DeviceObject = pDeviceObject; 351 pGraphicsDevice->FileObject = pFileObject; 352 353 /* Initialize and register the device with videoprt for Win32k callbacks */ 354 Win32kCallbacks.PhysDisp = pGraphicsDevice; 355 Win32kCallbacks.Callout = VideoPortCallout; 356 // Reset the data being returned prior to the call. 357 Win32kCallbacks.bACPI = FALSE; 358 Win32kCallbacks.pPhysDeviceObject = NULL; 359 Win32kCallbacks.DualviewFlags = 0; 360 Status = (NTSTATUS)EngDeviceIoControl((HANDLE)pDeviceObject, 361 IOCTL_VIDEO_INIT_WIN32K_CALLBACKS, 362 &Win32kCallbacks, 363 sizeof(Win32kCallbacks), 364 &Win32kCallbacks, 365 sizeof(Win32kCallbacks), 366 &ulReturn); 367 if (Status != ERROR_SUCCESS) 368 { 369 ERR("EngDeviceIoControl(0x%p, IOCTL_VIDEO_INIT_WIN32K_CALLBACKS) failed, Status 0x%lx\n", 370 pDeviceObject, Status); 371 } 372 // TODO: Set flags according to the results. 373 // if (Win32kCallbacks.bACPI) 374 // if (Win32kCallbacks.DualviewFlags & ???) 375 pGraphicsDevice->PhysDeviceHandle = Win32kCallbacks.pPhysDeviceObject; 376 377 /* FIXME: Enumerate children monitor devices for this video adapter 378 * 379 * - Force the adapter to re-enumerate its monitors: 380 * IoSynchronousInvalidateDeviceRelations(pdo, BusRelations) 381 * 382 * - Retrieve all monitor PDOs from VideoPrt: 383 * EngDeviceIoControl(0x%p, IOCTL_VIDEO_ENUM_MONITOR_PDO) 384 * 385 * - Initialize these fields and structures accordingly: 386 * pGraphicsDevice->dwMonCnt 387 * pGraphicsDevice->pvMonDev[0..dwMonCnt-1] 388 */ 389 390 /* Copy the device name */ 391 RtlStringCbCopyNW(pGraphicsDevice->szNtDeviceName, 392 sizeof(pGraphicsDevice->szNtDeviceName), 393 pustrDeviceName->Buffer, 394 pustrDeviceName->Length); 395 396 /* Create a Win32 device name (FIXME: virtual devices!) */ 397 RtlStringCbPrintfW(pGraphicsDevice->szWinDeviceName, 398 sizeof(pGraphicsDevice->szWinDeviceName), 399 L"\\\\.\\DISPLAY%d", 400 (int)giDevNum); 401 402 /* Allocate a buffer for the strings */ 403 cj = pustrDiplayDrivers->Length + pustrDescription->Length + sizeof(WCHAR); 404 pwsz = ExAllocatePoolWithTag(PagedPool, cj, GDITAG_DRVSUP); 405 if (!pwsz) 406 { 407 ERR("Could not allocate string buffer\n"); 408 ASSERT(FALSE); // FIXME 409 ExFreePoolWithTag(pGraphicsDevice, GDITAG_GDEVICE); 410 return NULL; 411 } 412 413 /* Copy the display driver names */ 414 pGraphicsDevice->pDiplayDrivers = pwsz; 415 RtlCopyMemory(pGraphicsDevice->pDiplayDrivers, 416 pustrDiplayDrivers->Buffer, 417 pustrDiplayDrivers->Length); 418 419 /* Copy the description */ 420 pGraphicsDevice->pwszDescription = pwsz + pustrDiplayDrivers->Length / sizeof(WCHAR); 421 RtlCopyMemory(pGraphicsDevice->pwszDescription, 422 pustrDescription->Buffer, 423 pustrDescription->Length); 424 pGraphicsDevice->pwszDescription[pustrDescription->Length/sizeof(WCHAR)] = 0; 425 426 /* Initialize the pdevmodeInfo list */ 427 pGraphicsDevice->pdevmodeInfo = NULL; 428 429 // FIXME: initialize state flags 430 pGraphicsDevice->StateFlags = 0; 431 432 /* Create the mode list */ 433 pGraphicsDevice->pDevModeList = NULL; 434 435 /* Lock loader */ 436 EngAcquireSemaphore(ghsemGraphicsDeviceList); 437 438 /* Insert the device into the global list */ 439 pGraphicsDevice->pNextGraphicsDevice = NULL; 440 if (gpGraphicsDeviceLast) 441 gpGraphicsDeviceLast->pNextGraphicsDevice = pGraphicsDevice; 442 gpGraphicsDeviceLast = pGraphicsDevice; 443 if (!gpGraphicsDeviceFirst) 444 gpGraphicsDeviceFirst = pGraphicsDevice; 445 446 /* Increment the device number */ 447 giDevNum++; 448 449 /* Unlock loader */ 450 EngReleaseSemaphore(ghsemGraphicsDeviceList); 451 TRACE("Prepared %lu modes for %ls\n", pGraphicsDevice->cDevModes, pGraphicsDevice->pwszDescription); 452 453 /* HACK: already in graphic mode; display wallpaper on this new display */ 454 if (ScreenDeviceContext) 455 { 456 UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY"); 457 UNICODE_STRING DisplayName; 458 HDC hdc; 459 RtlInitUnicodeString(&DisplayName, pGraphicsDevice->szWinDeviceName); 460 hdc = IntGdiCreateDC(&DriverName, &DisplayName, NULL, NULL, FALSE); 461 IntPaintDesktop(hdc); 462 } 463 464 return pGraphicsDevice; 465 } 466 467 PGRAPHICS_DEVICE 468 NTAPI 469 EngpFindGraphicsDevice( 470 _In_opt_ PUNICODE_STRING pustrDevice, 471 _In_ ULONG iDevNum) 472 { 473 UNICODE_STRING ustrCurrent; 474 PGRAPHICS_DEVICE pGraphicsDevice; 475 ULONG i; 476 TRACE("EngpFindGraphicsDevice('%wZ', %lu)\n", 477 pustrDevice, iDevNum); 478 479 /* Lock list */ 480 EngAcquireSemaphore(ghsemGraphicsDeviceList); 481 482 if (pustrDevice && pustrDevice->Buffer) 483 { 484 /* Find specified video adapter by name */ 485 for (pGraphicsDevice = gpGraphicsDeviceFirst; 486 pGraphicsDevice; 487 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice) 488 { 489 /* Compare the device name */ 490 RtlInitUnicodeString(&ustrCurrent, pGraphicsDevice->szWinDeviceName); 491 if (RtlEqualUnicodeString(&ustrCurrent, pustrDevice, FALSE)) 492 { 493 break; 494 } 495 } 496 497 if (pGraphicsDevice) 498 { 499 /* Validate selected monitor number */ 500 #if 0 501 if (iDevNum >= pGraphicsDevice->dwMonCnt) 502 pGraphicsDevice = NULL; 503 #else 504 /* FIXME: dwMonCnt not initialized, see EngpRegisterGraphicsDevice */ 505 #endif 506 } 507 } 508 else 509 { 510 /* Select video adapter by device number */ 511 for (pGraphicsDevice = gpGraphicsDeviceFirst, i = 0; 512 pGraphicsDevice && i < iDevNum; 513 pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice, i++); 514 } 515 516 /* Unlock list */ 517 EngReleaseSemaphore(ghsemGraphicsDeviceList); 518 519 return pGraphicsDevice; 520 } 521 522 static 523 NTSTATUS 524 EngpFileIoRequest( 525 _In_ PFILE_OBJECT pFileObject, 526 _In_ ULONG ulMajorFunction, 527 _In_reads_(nBufferSize) PVOID lpBuffer, 528 _In_ SIZE_T nBufferSize, 529 _In_ ULONGLONG ullStartOffset, 530 _Out_ PULONG_PTR lpInformation) 531 { 532 PDEVICE_OBJECT pDeviceObject; 533 KEVENT Event; 534 PIRP pIrp; 535 IO_STATUS_BLOCK Iosb; 536 NTSTATUS Status; 537 LARGE_INTEGER liStartOffset; 538 539 /* Get corresponding device object */ 540 pDeviceObject = IoGetRelatedDeviceObject(pFileObject); 541 if (!pDeviceObject) 542 { 543 return STATUS_INVALID_PARAMETER; 544 } 545 546 /* Initialize an event */ 547 KeInitializeEvent(&Event, SynchronizationEvent, FALSE); 548 549 /* Build IRP */ 550 liStartOffset.QuadPart = ullStartOffset; 551 pIrp = IoBuildSynchronousFsdRequest(ulMajorFunction, 552 pDeviceObject, 553 lpBuffer, 554 (ULONG)nBufferSize, 555 &liStartOffset, 556 &Event, 557 &Iosb); 558 if (!pIrp) 559 { 560 return STATUS_INSUFFICIENT_RESOURCES; 561 } 562 563 /* Call the driver */ 564 Status = IoCallDriver(pDeviceObject, pIrp); 565 566 /* Wait if neccessary */ 567 if (STATUS_PENDING == Status) 568 { 569 KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0); 570 Status = Iosb.Status; 571 } 572 573 /* Return information to the caller about the operation. */ 574 *lpInformation = Iosb.Information; 575 576 /* Return NTSTATUS */ 577 return Status; 578 } 579 580 VOID 581 APIENTRY 582 EngFileWrite( 583 _In_ PFILE_OBJECT pFileObject, 584 _In_reads_(nLength) PVOID lpBuffer, 585 _In_ SIZE_T nLength, 586 _Out_ PSIZE_T lpBytesWritten) 587 { 588 NTSTATUS status; 589 590 status = EngpFileIoRequest(pFileObject, 591 IRP_MJ_WRITE, 592 lpBuffer, 593 nLength, 594 0, 595 lpBytesWritten); 596 if (!NT_SUCCESS(status)) 597 { 598 *lpBytesWritten = 0; 599 } 600 } 601 602 _Success_(return>=0) 603 NTSTATUS 604 APIENTRY 605 EngFileIoControl( 606 _In_ PFILE_OBJECT pFileObject, 607 _In_ DWORD dwIoControlCode, 608 _In_reads_(nInBufferSize) PVOID lpInBuffer, 609 _In_ SIZE_T nInBufferSize, 610 _Out_writes_(nOutBufferSize) PVOID lpOutBuffer, 611 _In_ SIZE_T nOutBufferSize, 612 _Out_ PULONG_PTR lpInformation) 613 { 614 PDEVICE_OBJECT pDeviceObject; 615 KEVENT Event; 616 PIRP pIrp; 617 IO_STATUS_BLOCK Iosb; 618 NTSTATUS Status; 619 620 /* Get corresponding device object */ 621 pDeviceObject = IoGetRelatedDeviceObject(pFileObject); 622 if (!pDeviceObject) 623 { 624 return STATUS_INVALID_PARAMETER; 625 } 626 627 /* Initialize an event */ 628 KeInitializeEvent(&Event, SynchronizationEvent, FALSE); 629 630 /* Build IO control IRP */ 631 pIrp = IoBuildDeviceIoControlRequest(dwIoControlCode, 632 pDeviceObject, 633 lpInBuffer, 634 (ULONG)nInBufferSize, 635 lpOutBuffer, 636 (ULONG)nOutBufferSize, 637 FALSE, 638 &Event, 639 &Iosb); 640 if (!pIrp) 641 { 642 return STATUS_INSUFFICIENT_RESOURCES; 643 } 644 645 /* Call the driver */ 646 Status = IoCallDriver(pDeviceObject, pIrp); 647 648 /* Wait if neccessary */ 649 if (Status == STATUS_PENDING) 650 { 651 KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0); 652 Status = Iosb.Status; 653 } 654 655 /* Return information to the caller about the operation. */ 656 *lpInformation = Iosb.Information; 657 658 /* This function returns NTSTATUS */ 659 return Status; 660 } 661 662 /* 663 * @implemented 664 */ 665 _Success_(return==0) 666 DWORD 667 APIENTRY 668 EngDeviceIoControl( 669 _In_ HANDLE hDevice, 670 _In_ DWORD dwIoControlCode, 671 _In_reads_bytes_opt_(cjInBufferSize) LPVOID lpInBuffer, 672 _In_ DWORD cjInBufferSize, 673 _Out_writes_bytes_opt_(cjOutBufferSize) LPVOID lpOutBuffer, 674 _In_ DWORD cjOutBufferSize, 675 _Out_ LPDWORD lpBytesReturned) 676 { 677 PIRP Irp; 678 NTSTATUS Status; 679 KEVENT Event; 680 IO_STATUS_BLOCK Iosb; 681 PDEVICE_OBJECT DeviceObject; 682 683 TRACE("EngDeviceIoControl() called\n"); 684 685 if (!hDevice) 686 { 687 return ERROR_INVALID_HANDLE; 688 } 689 690 KeInitializeEvent(&Event, SynchronizationEvent, FALSE); 691 692 DeviceObject = (PDEVICE_OBJECT) hDevice; 693 694 Irp = IoBuildDeviceIoControlRequest(dwIoControlCode, 695 DeviceObject, 696 lpInBuffer, 697 cjInBufferSize, 698 lpOutBuffer, 699 cjOutBufferSize, 700 FALSE, 701 &Event, 702 &Iosb); 703 if (!Irp) return ERROR_NOT_ENOUGH_MEMORY; 704 705 Status = IoCallDriver(DeviceObject, Irp); 706 707 if (Status == STATUS_PENDING) 708 { 709 (VOID)KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0); 710 Status = Iosb.Status; 711 } 712 713 TRACE("EngDeviceIoControl(): Returning %X/%X\n", Iosb.Status, 714 Iosb.Information); 715 716 /* Return information to the caller about the operation. */ 717 *lpBytesReturned = (DWORD)Iosb.Information; 718 719 /* Convert NT status values to win32 error codes. */ 720 switch (Status) 721 { 722 case STATUS_INSUFFICIENT_RESOURCES: 723 return ERROR_NOT_ENOUGH_MEMORY; 724 725 case STATUS_BUFFER_OVERFLOW: 726 return ERROR_MORE_DATA; 727 728 case STATUS_NOT_IMPLEMENTED: 729 return ERROR_INVALID_FUNCTION; 730 731 case STATUS_INVALID_PARAMETER: 732 return ERROR_INVALID_PARAMETER; 733 734 case STATUS_BUFFER_TOO_SMALL: 735 return ERROR_INSUFFICIENT_BUFFER; 736 737 case STATUS_DEVICE_DOES_NOT_EXIST: 738 return ERROR_DEV_NOT_EXIST; 739 740 case STATUS_PENDING: 741 return ERROR_IO_PENDING; 742 } 743 744 return Status; 745 } 746 747 /* EOF */ 748