1 /*-- 2 3 Copyright (C) Microsoft Corporation. All rights reserved. 4 5 Module Name: 6 7 cdrom.c 8 9 Abstract: 10 11 The CDROM class driver tranlates IRPs to SRBs with embedded CDBs 12 and sends them to its devices through the port driver. 13 14 Environment: 15 16 kernel mode only 17 18 Notes: 19 20 21 Revision History: 22 23 --*/ 24 25 // this definition is used to link _StorDebugPrint() function. 26 #define DEBUG_MAIN_SOURCE 1 27 28 29 #include "ntddk.h" 30 #include "ntstrsafe.h" 31 32 #include "ntddstor.h" 33 #include "ntddtape.h" 34 #include "wdfcore.h" 35 #include "devpkey.h" 36 37 #include "cdrom.h" 38 #include "ioctl.h" 39 #include "mmc.h" 40 #include "scratch.h" 41 42 43 #ifdef DEBUG_USE_WPP 44 #include "cdrom.tmh" 45 #endif 46 47 BOOLEAN 48 BootEnvironmentIsWinPE( 49 VOID 50 ); 51 52 #ifdef ALLOC_PRAGMA 53 54 #pragma alloc_text(INIT, DriverEntry) 55 #pragma alloc_text(INIT, BootEnvironmentIsWinPE) 56 57 #pragma alloc_text(PAGE, DriverEvtCleanup) 58 #pragma alloc_text(PAGE, DriverEvtDeviceAdd) 59 #pragma alloc_text(PAGE, DeviceEvtCleanup) 60 #pragma alloc_text(PAGE, DeviceEvtSelfManagedIoCleanup) 61 #pragma alloc_text(PAGE, DeviceEvtD0Exit) 62 #pragma alloc_text(PAGE, CreateQueueEvtIoDefault) 63 #pragma alloc_text(PAGE, DeviceEvtFileClose) 64 #pragma alloc_text(PAGE, DeviceCleanupProtectedLocks) 65 #pragma alloc_text(PAGE, DeviceCleanupDisableMcn) 66 #pragma alloc_text(PAGE, RequestProcessSerializedIoctl) 67 #pragma alloc_text(PAGE, ReadWriteWorkItemRoutine) 68 #pragma alloc_text(PAGE, IoctlWorkItemRoutine) 69 #pragma alloc_text(PAGE, DeviceEvtSurpriseRemoval) 70 71 #endif 72 73 NTSTATUS 74 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 75 DriverEntry( 76 _In_ PDRIVER_OBJECT DriverObject, 77 _In_ PUNICODE_STRING RegistryPath 78 ) 79 /*++ 80 81 Routine Description: 82 83 Installable driver initialization entry point. 84 This entry point is called directly by the I/O system. 85 86 Arguments: 87 88 DriverObject - pointer to the driver object 89 90 RegistryPath - pointer to a unicode string representing the path, 91 to driver-specific key in the registry. 92 93 Return Value: 94 95 STATUS_SUCCESS if successful, 96 STATUS_UNSUCCESSFUL otherwise. 97 98 --*/ 99 { 100 NTSTATUS status; 101 WDF_DRIVER_CONFIG config; 102 WDF_OBJECT_ATTRIBUTES attributes; 103 WDFDRIVER driverObject = NULL; 104 105 PAGED_CODE(); 106 107 // Initialize WPP Tracing 108 WPP_INIT_TRACING(DriverObject, RegistryPath); 109 110 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, 111 "CDROM.SYS DriverObject %p loading\n", 112 DriverObject)); 113 114 // Register DeviceAdd and DriverEvtCleanup callback. 115 // WPP_CLEANUP will be called in DriverEvtCleanup 116 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CDROM_DRIVER_EXTENSION); 117 attributes.EvtCleanupCallback = DriverEvtCleanup; 118 119 WDF_DRIVER_CONFIG_INIT(&config, DriverEvtDeviceAdd); 120 121 status = WdfDriverCreate(DriverObject, 122 RegistryPath, 123 &attributes, 124 &config, 125 &driverObject); 126 127 if (!NT_SUCCESS(status)) 128 { 129 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT, 130 "WdfDriverCreate failed. %x\n", 131 status)); 132 133 // Cleanup tracing here because DriverUnload will not be called 134 // as we have failed to create WDFDRIVER object itself. 135 WPP_CLEANUP(DriverObject); 136 137 } 138 else 139 { 140 PCDROM_DRIVER_EXTENSION driverExtension = DriverGetExtension(driverObject); 141 142 // Copy the registry path into the driver extension so we can use it later 143 driverExtension->Version = 0x01; 144 driverExtension->DriverObject = DriverObject; 145 146 if (BootEnvironmentIsWinPE()) { 147 148 SET_FLAG(driverExtension->Flags, CDROM_FLAG_WINPE_MODE); 149 } 150 151 } 152 153 return status; 154 } 155 156 157 BOOLEAN 158 BootEnvironmentIsWinPE( 159 VOID 160 ) 161 /*++ 162 163 Routine Description: 164 165 This routine determines if the boot enviroment is WinPE 166 167 Arguments: 168 169 None 170 171 Return Value: 172 173 BOOLEAN - TRUE if the environment is WinPE; FALSE otherwise 174 175 --*/ 176 { 177 NTSTATUS status; 178 WDFKEY registryKey = NULL; 179 180 DECLARE_CONST_UNICODE_STRING(registryKeyName, WINPE_REG_KEY_NAME); 181 182 PAGED_CODE(); 183 184 status = WdfRegistryOpenKey(NULL, 185 ®istryKeyName, 186 KEY_READ, 187 WDF_NO_OBJECT_ATTRIBUTES, 188 ®istryKey); 189 190 if (!NT_SUCCESS(status)) 191 { 192 return FALSE; 193 } 194 195 WdfRegistryClose(registryKey); 196 return TRUE; 197 } // end BootEnvironmentIsWinPE() 198 199 200 VOID 201 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 202 DriverEvtCleanup( 203 _In_ WDFOBJECT Driver 204 ) 205 /*++ 206 Routine Description: 207 208 Free all the resources allocated in DriverEntry. 209 210 Arguments: 211 212 Driver - handle to a WDF Driver object. 213 214 Return Value: 215 216 VOID. 217 218 --*/ 219 { 220 WDFDRIVER driver = (WDFDRIVER)Driver; 221 222 PAGED_CODE (); 223 224 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, 225 "CDROM.SYS DriverObject %p cleanup. Will be unloaded soon\n", 226 driver)); 227 228 // Stop WPP Tracing 229 WPP_CLEANUP( WdfDriverWdmGetDriverObject(driver) ); 230 231 232 return; 233 } 234 235 236 NTSTATUS 237 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 238 DriverEvtDeviceAdd( 239 _In_ WDFDRIVER Driver, 240 _Inout_ PWDFDEVICE_INIT DeviceInit 241 ) 242 /*++ 243 244 Routine Description: 245 246 EvtDeviceAdd is called by the framework in response to AddDevice 247 call from the PnP manager. 248 249 250 Arguments: 251 252 Driver - Handle to a framework driver object created in DriverEntry 253 254 DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. 255 256 Return Value: 257 258 NTSTATUS 259 260 --*/ 261 { 262 NTSTATUS status = STATUS_SUCCESS; 263 PCDROM_DRIVER_EXTENSION driverExtension = NULL; 264 WDFDEVICE device = NULL; 265 PCDROM_DEVICE_EXTENSION deviceExtension = NULL; 266 BOOLEAN deviceClaimed = FALSE; 267 268 WDF_OBJECT_ATTRIBUTES attributes; 269 WDF_FILEOBJECT_CONFIG fileObjectConfig; 270 WDF_IO_TARGET_OPEN_PARAMS ioTargetOpenParams; 271 WDF_IO_QUEUE_CONFIG queueConfig; 272 WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; 273 WDF_REMOVE_LOCK_OPTIONS removeLockOptions; 274 PWCHAR wideDeviceName = NULL; 275 UNICODE_STRING unicodeDeviceName; 276 PDEVICE_OBJECT lowerPdo = NULL; 277 ULONG deviceNumber = 0; 278 ULONG devicePropertySessionId = INVALID_SESSION; 279 ULONG devicePropertySize = 0; 280 DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY; 281 282 PAGED_CODE(); 283 284 driverExtension = DriverGetExtension(Driver); 285 286 // 0. Initialize the objects that we're going to use 287 RtlInitUnicodeString(&unicodeDeviceName, NULL); 288 289 // 1. Register PnP&Power callbacks for any we are interested in. 290 // If a callback isn't set, Framework will take the default action by itself. 291 { 292 // Zero out the PnpPowerCallbacks structure. 293 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); 294 295 // Use this callback to init resources that are used by the device and only needs to be called once. 296 pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = DeviceEvtSelfManagedIoInit; 297 298 // Use this callback to prepare device for coming back from a lower power mode to D0. 299 pnpPowerCallbacks.EvtDeviceD0Entry = DeviceEvtD0Entry; 300 301 // Use this callback to prepare device for entering into a lower power mode. 302 pnpPowerCallbacks.EvtDeviceD0Exit = DeviceEvtD0Exit; 303 304 // Use this callback to free any resources used by device and will be called when the device is 305 // powered down. 306 pnpPowerCallbacks.EvtDeviceSelfManagedIoCleanup = DeviceEvtSelfManagedIoCleanup; 307 308 pnpPowerCallbacks.EvtDeviceSurpriseRemoval = DeviceEvtSurpriseRemoval; 309 310 // Register the PnP and power callbacks. 311 WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); 312 } 313 314 // 2. Register the EvtIoInCallerContext to deal with IOCTLs that need to stay in original context. 315 WdfDeviceInitSetIoInCallerContextCallback(DeviceInit, 316 DeviceEvtIoInCallerContext); 317 318 // 3. Register PreprocessCallback for IRP_MJ_POWER, IRP_MJ_FLUSH_BUFFERS and IRP_MJ_SHUTDOWN 319 { 320 UCHAR minorFunctions[1]; 321 322 minorFunctions[0] = IRP_MN_SET_POWER; 323 324 status = WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit, 325 RequestProcessSetPower, 326 IRP_MJ_POWER, 327 minorFunctions, 328 RTL_NUMBER_OF(minorFunctions)); 329 if (!NT_SUCCESS(status)) 330 { 331 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, 332 "DriverEvtDeviceAdd: Assign IrpPreprocessCallback for IRP_MJ_POWER failed, " 333 "status: 0x%X\n", status)); 334 335 goto Exit; 336 } 337 338 status = WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit, 339 RequestProcessShutdownFlush, 340 IRP_MJ_FLUSH_BUFFERS, 341 NULL, 342 0); 343 if (!NT_SUCCESS(status)) 344 { 345 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, 346 "DriverEvtDeviceAdd: Assign IrpPreprocessCallback for IRP_MJ_FLUSH_BUFFERS failed, " 347 "status: 0x%X\n", status)); 348 349 goto Exit; 350 } 351 352 status = WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit, 353 RequestProcessShutdownFlush, 354 IRP_MJ_SHUTDOWN, 355 NULL, 356 0); 357 if (!NT_SUCCESS(status)) 358 { 359 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, 360 "DriverEvtDeviceAdd: Assign IrpPreprocessCallback for IRP_MJ_SHUTDOWN failed, " 361 "status: 0x%X\n", status)); 362 363 goto Exit; 364 } 365 } 366 367 // 4. Set attributes to create Request Context area. 368 { 369 //Reuse this structure. 370 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, 371 CDROM_REQUEST_CONTEXT); 372 attributes.EvtCleanupCallback = RequestEvtCleanup; 373 374 WdfDeviceInitSetRequestAttributes(DeviceInit, 375 &attributes); 376 } 377 378 // 5. Register FileObject related callbacks 379 { 380 // Add FILE_OBJECT_EXTENSION as the context to the file object. 381 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FILE_OBJECT_CONTEXT); 382 383 // Set Entry points for Create and Close.. 384 385 // The framework doesn't sync the file create requests with pnp/power 386 // state. Re-direct all the file create requests to a dedicated 387 // queue, which will be purged manually during removal. 388 WDF_FILEOBJECT_CONFIG_INIT(&fileObjectConfig, 389 NULL, //CreateQueueEvtIoDefault, 390 DeviceEvtFileClose, 391 WDF_NO_EVENT_CALLBACK); // No callback for Cleanup 392 393 fileObjectConfig.FileObjectClass = WdfFileObjectWdfCannotUseFsContexts; 394 395 // Since we are registering file events and fowarding create request 396 // ourself, we must also set AutoForwardCleanupClose so that cleanup 397 // and close can also get forwarded. 398 fileObjectConfig.AutoForwardCleanupClose = WdfTrue; 399 attributes.SynchronizationScope = WdfSynchronizationScopeNone; 400 attributes.ExecutionLevel = WdfExecutionLevelPassive; 401 402 // Indicate that file object is optional. 403 fileObjectConfig.FileObjectClass |= WdfFileObjectCanBeOptional; 404 405 WdfDeviceInitSetFileObjectConfig(DeviceInit, 406 &fileObjectConfig, 407 &attributes); 408 } 409 410 // 6. Initialize device-wide attributes 411 { 412 // Declare ourselves as NOT owning power policy. 413 // The power policy owner in storage stack is port driver. 414 WdfDeviceInitSetPowerPolicyOwnership(DeviceInit, FALSE); 415 416 // Set other DeviceInit attributes. 417 WdfDeviceInitSetExclusive(DeviceInit, FALSE); 418 WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_CD_ROM); 419 WdfDeviceInitSetCharacteristics(DeviceInit, FILE_REMOVABLE_MEDIA, FALSE); 420 WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect); 421 WdfDeviceInitSetPowerPageable(DeviceInit); 422 423 // We require the framework to acquire a remove lock before delivering all IRP types 424 WDF_REMOVE_LOCK_OPTIONS_INIT(&removeLockOptions, 425 WDF_REMOVE_LOCK_OPTION_ACQUIRE_FOR_IO); 426 427 WdfDeviceInitSetRemoveLockOptions(DeviceInit, &removeLockOptions); 428 429 // save the PDO for later reference 430 lowerPdo = WdfFdoInitWdmGetPhysicalDevice(DeviceInit); 431 432 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, 433 CDROM_DEVICE_EXTENSION); 434 435 // We have a parallel queue, so WdfSynchronizationScopeNone is our only choice. 436 attributes.SynchronizationScope = WdfSynchronizationScopeNone; 437 attributes.ExecutionLevel = WdfExecutionLevelDispatch; 438 439 // Provide a cleanup callback which will release memory allocated with ExAllocatePool* 440 attributes.EvtCleanupCallback = DeviceEvtCleanup; 441 } 442 443 // 7. Now, the device can be created. 444 { 445 wideDeviceName = ExAllocatePoolWithTag(NonPagedPoolNx, 446 64 * sizeof(WCHAR), 447 CDROM_TAG_STRINGS); 448 449 if (wideDeviceName == NULL) 450 { 451 status = STATUS_INSUFFICIENT_RESOURCES; 452 goto Exit; 453 } 454 455 // Find the lowest device number currently available. 456 do { 457 status = RtlStringCchPrintfW((NTSTRSAFE_PWSTR)wideDeviceName, 458 64, 459 L"\\Device\\CdRom%d", 460 deviceNumber); 461 462 if (!NT_SUCCESS(status)) { 463 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, 464 "DriverEvtDeviceAdd: Format device name failed with error: 0x%X\n", status)); 465 466 goto Exit; 467 } 468 469 RtlInitUnicodeString(&unicodeDeviceName, wideDeviceName); 470 471 status = WdfDeviceInitAssignName(DeviceInit, &unicodeDeviceName); 472 if (!NT_SUCCESS(status)) 473 { 474 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, 475 "DriverEvtDeviceAdd: WdfDeviceInitAssignName() failed with error: 0x%X\n", status)); 476 477 goto Exit; 478 } 479 480 status = WdfDeviceCreate(&DeviceInit, &attributes, &device); 481 482 deviceNumber++; 483 484 } while (status == STATUS_OBJECT_NAME_COLLISION); 485 486 // When this loop exits the count is inflated by one - fix that. 487 deviceNumber--; 488 489 if (!NT_SUCCESS(status)) 490 { 491 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, 492 "DriverEvtDeviceAdd: Can not create a new device, status: 0x%X\n", 493 status)); 494 495 goto Exit; 496 } 497 } 498 499 // 8. Fill up basic Device Extension settings and create a remote I/O target for the next-lower driver. 500 // The reason why we do not use the local I/O target is because we want to be able to close the 501 // I/O target on surprise removal. 502 { 503 deviceExtension = DeviceGetExtension(device); 504 505 deviceExtension->Version = 0x01; 506 deviceExtension->Size = sizeof(CDROM_DEVICE_EXTENSION); 507 508 deviceExtension->DeviceObject = WdfDeviceWdmGetDeviceObject(device); 509 deviceExtension->Device = device; 510 deviceExtension->DriverExtension = driverExtension; 511 512 deviceExtension->LowerPdo = lowerPdo; 513 514 deviceExtension->DeviceType = FILE_DEVICE_CD_ROM; //Always a FILE_DEVICE_CD_ROM for all device it manages. 515 deviceExtension->DeviceName = unicodeDeviceName; 516 517 deviceExtension->DeviceNumber = deviceNumber; 518 } 519 { 520 WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 521 attributes.ParentObject = deviceExtension->Device; 522 523 status = WdfIoTargetCreate(deviceExtension->Device, 524 &attributes, 525 &deviceExtension->IoTarget); 526 527 if (!NT_SUCCESS(status)) 528 { 529 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, 530 "DriverEvtDeviceAdd: Can not create a remote I/O target object, status: 0x%X\n", 531 status)); 532 goto Exit; 533 } 534 535 WDF_IO_TARGET_OPEN_PARAMS_INIT_EXISTING_DEVICE(&ioTargetOpenParams, 536 WdfDeviceWdmGetAttachedDevice(deviceExtension->Device)); 537 538 status = WdfIoTargetOpen(deviceExtension->IoTarget, 539 &ioTargetOpenParams); 540 if (!NT_SUCCESS(status)) 541 { 542 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, 543 "DriverEvtDeviceAdd: Can not open a remote I/O target for the next-lower device, status: 0x%X\n", 544 status)); 545 546 WdfObjectDelete(deviceExtension->IoTarget); 547 deviceExtension->IoTarget = NULL; 548 549 goto Exit; 550 } 551 } 552 553 // 9. Claim the device, so that port driver will only accept the commands from CDROM.SYS for this device. 554 // NOTE: The I/O should be issued after the device is started. But we would like to claim 555 // the device as soon as possible, so this legacy behavior is kept. 556 status = DeviceClaimRelease(deviceExtension, FALSE); 557 558 if (!NT_SUCCESS(status)) 559 { 560 // Someone already had this device - we're in trouble 561 goto Exit; 562 } 563 else 564 { 565 deviceClaimed = TRUE; 566 } 567 568 // 569 // CDROM Queueing Structure 570 // 571 // a. EvtIoInCallerContext (prior to queueing): 572 // This event will be used ONLY to forward down IOCTLs that come in at PASSIVE LEVEL 573 // and need to be forwarded down the stack in the original context. 574 // 575 // b. Main input queue: serial queue for main dispatching 576 // This queue will be used to do all dispatching of requests to serialize 577 // access to the device. Any request that was previously completed in 578 // the Dispatch routines will be completed here. Anything requiring device 579 // I/O will be sent through the serial I/O queue. 580 // 581 // 10. Set up IO queues after device being created. 582 // 583 { 584 WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, 585 WdfIoQueueDispatchSequential); 586 587 queueConfig.PowerManaged = WdfFalse; 588 589 #pragma prefast(push) 590 #pragma prefast(disable: 28155, "a joint handler for read/write cannot be EVT_WDF_IO_QUEUE_IO_READ and EVT_WDF_IO_QUEUE_IO_WRITE simultaneously") 591 #pragma prefast(disable: 28023, "a joint handler for read/write cannot be EVT_WDF_IO_QUEUE_IO_READ and EVT_WDF_IO_QUEUE_IO_WRITE simultaneously") 592 queueConfig.EvtIoRead = SequentialQueueEvtIoReadWrite; 593 queueConfig.EvtIoWrite = SequentialQueueEvtIoReadWrite; 594 #pragma prefast(pop) 595 596 queueConfig.EvtIoDeviceControl = SequentialQueueEvtIoDeviceControl; 597 queueConfig.EvtIoCanceledOnQueue = SequentialQueueEvtCanceledOnQueue; 598 599 status = WdfIoQueueCreate(device, 600 &queueConfig, 601 WDF_NO_OBJECT_ATTRIBUTES, 602 &(deviceExtension->SerialIOQueue)); 603 if (!NT_SUCCESS(status)) 604 { 605 goto Exit; 606 } 607 608 // this queue is dedicated for file create requests. 609 WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchParallel); 610 611 queueConfig.PowerManaged = WdfFalse; 612 queueConfig.EvtIoDefault = CreateQueueEvtIoDefault; 613 614 //Reuse this structure. 615 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, 616 CDROM_REQUEST_CONTEXT); 617 618 attributes.SynchronizationScope = WdfSynchronizationScopeNone; 619 attributes.ExecutionLevel = WdfExecutionLevelPassive; 620 621 status = WdfIoQueueCreate(device, 622 &queueConfig, 623 &attributes, 624 &(deviceExtension->CreateQueue)); 625 626 if (!NT_SUCCESS(status)) 627 { 628 goto Exit; 629 } 630 631 // Configure the device to use driver created queue for dispatching create. 632 status = WdfDeviceConfigureRequestDispatching(device, 633 deviceExtension->CreateQueue, 634 WdfRequestTypeCreate); 635 636 if (!NT_SUCCESS(status)) 637 { 638 goto Exit; 639 } 640 } 641 642 // 11. Set the alignment requirements for the device based on the host adapter requirements. 643 // 644 // NOTE: this should have been set when device is attached on device stack, 645 // by keeping this legacy code, we could avoid issue that this value was not correctly set at that time. 646 if (deviceExtension->LowerPdo->AlignmentRequirement > deviceExtension->DeviceObject->AlignmentRequirement) 647 { 648 WdfDeviceSetAlignmentRequirement(deviceExtension->Device, 649 deviceExtension->LowerPdo->AlignmentRequirement); 650 } 651 652 // 12. Initialization of miscellaneous internal properties 653 654 // CDROMs are not partitionable so starting offset is 0. 655 deviceExtension->StartingOffset.LowPart = 0; 656 deviceExtension->StartingOffset.HighPart = 0; 657 658 // Set the default geometry for the cdrom to match what NT 4 used. 659 // these values will be used to compute the cylinder count rather 660 // than using it's NT 5.0 defaults. 661 deviceExtension->DiskGeometry.MediaType = RemovableMedia; 662 deviceExtension->DiskGeometry.TracksPerCylinder = 0x40; 663 deviceExtension->DiskGeometry.SectorsPerTrack = 0x20; 664 665 deviceExtension->DeviceAdditionalData.ReadWriteRetryDelay100nsUnits = WRITE_RETRY_DELAY_DVD_1x; 666 667 // Clear the SrbFlags and disable synchronous transfers 668 deviceExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 669 670 // Set timeout value in seconds. 671 deviceExtension->TimeOutValue = DeviceGetTimeOutValueFromRegistry(); 672 if ((deviceExtension->TimeOutValue > 30 * 60) || // longer than 30 minutes 673 (deviceExtension->TimeOutValue == 0)) 674 { 675 deviceExtension->TimeOutValue = SCSI_CDROM_TIMEOUT; 676 } 677 678 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, 679 "DriverEvtDeviceAdd: device timeout is set to %x seconds", 680 deviceExtension->TimeOutValue 681 )); 682 683 #if (NTDDI_VERSION >= NTDDI_WIN8) 684 deviceExtension->IsVolumeOnlinePending = TRUE; 685 686 WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); 687 688 queueConfig.PowerManaged = WdfFalse; 689 690 status = WdfIoQueueCreate(device, 691 &queueConfig, 692 WDF_NO_OBJECT_ATTRIBUTES, 693 &deviceExtension->ManualVolumeReadyQueue); 694 695 if (!NT_SUCCESS(status)) 696 { 697 goto Exit; 698 } 699 #endif 700 701 // 13. Initialize the stuff related to media locking 702 WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 703 attributes.ParentObject = deviceExtension->Device; 704 status = WdfWaitLockCreate(&attributes, 705 &deviceExtension->EjectSynchronizationLock); 706 707 deviceExtension->LockCount = 0; 708 709 // 14. Initialize context structures needed for asynchronous release queue and power requests 710 711 if (NT_SUCCESS(status)) 712 { 713 status = DeviceInitReleaseQueueContext(deviceExtension); 714 } 715 716 if (NT_SUCCESS(status)) 717 { 718 status = DeviceInitPowerContext(deviceExtension); 719 } 720 721 // 15. Create external access points other than device name. 722 if (NT_SUCCESS(status)) 723 { 724 status = DeviceCreateWellKnownName(deviceExtension); 725 } 726 727 // 16. Query session id from the PDO. 728 if (NT_SUCCESS(status)) 729 { 730 status = IoGetDevicePropertyData(deviceExtension->LowerPdo, 731 &DEVPKEY_Device_SessionId, 732 0, 733 0, 734 sizeof(devicePropertySessionId), 735 &devicePropertySessionId, 736 &devicePropertySize, 737 &devicePropertyType); 738 739 if (!NT_SUCCESS(status)) 740 { 741 // The device is global. 742 devicePropertySessionId = INVALID_SESSION; 743 status = STATUS_SUCCESS; 744 } 745 } 746 747 // 17. Register interfaces for this device. 748 if (NT_SUCCESS(status)) 749 { 750 status = DeviceRegisterInterface(deviceExtension, CdRomDeviceInterface); 751 } 752 753 if (NT_SUCCESS(status)) 754 { 755 // If this is a per-session DO, don't register for mount interface so that 756 // mountmgr will not automatically assign a drive letter. 757 if (devicePropertySessionId == INVALID_SESSION) 758 { 759 status = DeviceRegisterInterface(deviceExtension, MountedDeviceInterface); 760 } 761 } 762 763 // 18. Initialize the shutdown/flush lock 764 if (NT_SUCCESS(status)) 765 { 766 WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 767 attributes.ParentObject = deviceExtension->Device; 768 769 status = WdfWaitLockCreate(&attributes, &deviceExtension->ShutdownFlushWaitLock); 770 if (!NT_SUCCESS(status)) 771 { 772 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, 773 "DriverEvtDeviceAdd: Cannot create shutdown/flush waitlock, status: 0x%X\n", 774 status)); 775 } 776 } 777 778 // 19. Initialize the work item that is used to initiate asynchronous reads/writes 779 if (NT_SUCCESS(status)) 780 { 781 WDF_WORKITEM_CONFIG workItemConfig; 782 WDF_OBJECT_ATTRIBUTES workItemAttributes; 783 784 WDF_WORKITEM_CONFIG_INIT(&workItemConfig, 785 ReadWriteWorkItemRoutine 786 ); 787 788 WDF_OBJECT_ATTRIBUTES_INIT(&workItemAttributes); 789 workItemAttributes.ParentObject = deviceExtension->Device; 790 791 status = WdfWorkItemCreate(&workItemConfig, 792 &workItemAttributes, 793 &deviceExtension->ReadWriteWorkItem 794 ); 795 796 if (!NT_SUCCESS(status)) 797 { 798 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT, 799 "DriverEvtDeviceAdd: Cannot create read/write work item, status: 0x%X\n", 800 status)); 801 } 802 } 803 804 // 20. Initialize the work item that is used to process most IOCTLs at PASSIVE_LEVEL. 805 if (NT_SUCCESS(status)) 806 { 807 WDF_WORKITEM_CONFIG workItemConfig; 808 WDF_OBJECT_ATTRIBUTES workItemAttributes; 809 810 WDF_WORKITEM_CONFIG_INIT(&workItemConfig, 811 IoctlWorkItemRoutine 812 ); 813 814 WDF_OBJECT_ATTRIBUTES_INIT(&workItemAttributes); 815 workItemAttributes.ParentObject = deviceExtension->Device; 816 817 status = WdfWorkItemCreate(&workItemConfig, 818 &workItemAttributes, 819 &deviceExtension->IoctlWorkItem 820 ); 821 822 if (!NT_SUCCESS(status)) 823 { 824 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT, 825 "DriverEvtDeviceAdd: Cannot create ioctl work item, status: 0x%X\n", 826 status)); 827 } 828 } 829 830 831 Exit: 832 833 if (!NT_SUCCESS(status)) 834 { 835 FREE_POOL(wideDeviceName); 836 837 if (deviceExtension != NULL) 838 { 839 RtlInitUnicodeString(&deviceExtension->DeviceName, NULL); 840 } 841 842 // Release the device with the port driver, if it was claimed 843 if ((deviceExtension != NULL) && deviceClaimed) 844 { 845 DeviceClaimRelease(deviceExtension, TRUE); 846 } 847 deviceClaimed = FALSE; 848 } 849 850 return status; 851 } 852 853 854 VOID 855 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 856 DeviceEvtCleanup( 857 _In_ WDFOBJECT Device 858 ) 859 /*++ 860 Routine Description: 861 862 Free all the resources allocated in DriverEvtDeviceAdd. 863 864 Arguments: 865 866 Device - handle to a WDF Device object. 867 868 Return Value: 869 870 VOID. 871 872 --*/ 873 { 874 WDFDEVICE device = (WDFDEVICE)Device; 875 PCDROM_DEVICE_EXTENSION deviceExtension = NULL; 876 877 PAGED_CODE (); 878 879 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, 880 "WDFDEVICE %p cleanup: The device is about to be destroyed.\n", 881 device)); 882 883 deviceExtension = DeviceGetExtension(device); 884 885 FREE_POOL(deviceExtension->DeviceName.Buffer); 886 RtlInitUnicodeString(&deviceExtension->DeviceName, NULL); 887 888 if (deviceExtension->DeviceAdditionalData.WellKnownName.Buffer != NULL) 889 { 890 IoDeleteSymbolicLink(&deviceExtension->DeviceAdditionalData.WellKnownName); 891 } 892 893 FREE_POOL(deviceExtension->DeviceAdditionalData.WellKnownName.Buffer); 894 RtlInitUnicodeString(&deviceExtension->DeviceAdditionalData.WellKnownName, NULL); 895 896 return; 897 } 898 899 900 VOID 901 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 902 DeviceEvtSelfManagedIoCleanup( 903 _In_ WDFDEVICE Device 904 ) 905 /*++ 906 907 Routine Description: 908 909 this function is called when the device is removed. 910 release the ownership of the device, release allocated resources. 911 912 Arguments: 913 914 Device - Handle to device object 915 916 Return Value: 917 918 None. 919 920 --*/ 921 { 922 NTSTATUS status; 923 PCDROM_DEVICE_EXTENSION deviceExtension = NULL; 924 925 PAGED_CODE (); 926 927 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, 928 "DeviceEvtSelfManagedIoCleanup: WDFDEVICE %p is being stopped.\n", 929 Device)); 930 931 // extract the device and driver extensions 932 deviceExtension = DeviceGetExtension(Device); 933 934 // Purge unprocessed requests, stop the IO queues. 935 // Incoming request will be completed with STATUS_INVALID_DEVICE_STATE status. 936 WdfIoQueuePurge(deviceExtension->SerialIOQueue, WDF_NO_EVENT_CALLBACK, WDF_NO_CONTEXT); 937 WdfIoQueuePurge(deviceExtension->CreateQueue, WDF_NO_EVENT_CALLBACK, WDF_NO_CONTEXT); 938 939 // Close the IoTarget so that we are sure there are no outstanding I/Os in the stack. 940 if (deviceExtension->IoTarget) 941 { 942 WdfIoTargetClose(deviceExtension->IoTarget); 943 } 944 945 // Release the device 946 if (!deviceExtension->SurpriseRemoved) 947 { 948 status = DeviceClaimRelease(deviceExtension, TRUE); //status is mainly for debugging. we don't really care. 949 UNREFERENCED_PARAMETER(status); //defensive coding, avoid PREFAST warning. 950 } 951 952 // Be sure to flush the DPCs as the READ/WRITE timer routine may still be running 953 // during device removal. This call may take a while to complete. 954 KeFlushQueuedDpcs(); 955 956 // Release all the memory that we have allocated. 957 958 DeviceDeallocateMmcResources(Device); 959 ScratchBuffer_Deallocate(deviceExtension); 960 RtlZeroMemory(&(deviceExtension->DeviceAdditionalData.Mmc), sizeof(CDROM_MMC_EXTENSION)); 961 962 FREE_POOL(deviceExtension->DeviceDescriptor); 963 FREE_POOL(deviceExtension->AdapterDescriptor); 964 FREE_POOL(deviceExtension->PowerDescriptor); 965 FREE_POOL(deviceExtension->SenseData); 966 967 if (deviceExtension->DeviceAdditionalData.CachedInquiryData != NULL) 968 { 969 FREE_POOL(deviceExtension->DeviceAdditionalData.CachedInquiryData); 970 deviceExtension->DeviceAdditionalData.CachedInquiryDataByteCount = 0; 971 } 972 973 FREE_POOL(deviceExtension->PrivateFdoData); 974 975 DeviceReleaseMcnResources(deviceExtension); 976 977 DeviceReleaseZPODDResources(deviceExtension); 978 979 // Keep the system-wide CDROM count accurate, as programs use this info to 980 // know when they have found all the cdroms in a system. 981 IoGetConfigurationInformation()->CdRomCount--; 982 983 deviceExtension->PartitionLength.QuadPart = 0; 984 985 // All WDF objects related to Device will be automatically released 986 // when the root object is deleted. No need to release them manually. 987 988 return; 989 } 990 991 NTSTATUS 992 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 993 DeviceEvtD0Entry( 994 _In_ WDFDEVICE Device, 995 _In_ WDF_POWER_DEVICE_STATE PreviousState 996 ) 997 /*++ 998 999 Routine Description: 1000 1001 This function is called when the device is coming back from a lower power state to D0. 1002 This function cannot be placed in a pageable section. 1003 1004 Arguments: 1005 1006 Device - Handle to device object 1007 PreviousState - Power state the device was in. 1008 1009 Return Value: 1010 1011 NTSTATUS: alway STATUS_SUCCESS 1012 1013 --*/ 1014 { 1015 PCDROM_DEVICE_EXTENSION deviceExtension; 1016 NTSTATUS status = STATUS_SUCCESS; 1017 PZERO_POWER_ODD_INFO zpoddInfo = NULL; 1018 STORAGE_IDLE_POWERUP_REASON powerupReason = {0}; 1019 1020 UNREFERENCED_PARAMETER(PreviousState); 1021 deviceExtension = DeviceGetExtension(Device); 1022 1023 // Make certain not to do anything before properly initialized 1024 if (deviceExtension->IsInitialized) 1025 { 1026 zpoddInfo = deviceExtension->ZeroPowerODDInfo; 1027 1028 if (zpoddInfo != NULL) 1029 { 1030 if (zpoddInfo->InZeroPowerState != FALSE) 1031 { 1032 // We just woke up from Zero Power state 1033 zpoddInfo->InZeroPowerState = FALSE; 1034 zpoddInfo->RetryFirstCommand = TRUE; 1035 zpoddInfo->BecomingReadyRetryCount = BECOMING_READY_RETRY_COUNT; 1036 1037 status = DeviceZPODDGetPowerupReason(deviceExtension, &powerupReason); 1038 1039 if (NT_SUCCESS(status) && 1040 (powerupReason.PowerupReason == StoragePowerupDeviceAttention)) 1041 { 1042 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, 1043 "DeviceEvtD0Entry: Device has left zero power state due to eject button pressed\n" 1044 )); 1045 1046 // This wake-up is caused by user pressing the eject button. 1047 // In case of drawer type, we need to soft eject the tray to emulate the effect. 1048 // Note that the first command to the device after power resumed will 1049 // be terminated with CHECK CONDITION status with sense code 6/29/00, 1050 // but we already have a retry logic to handle this. 1051 if ((zpoddInfo->LoadingMechanism == LOADING_MECHANISM_TRAY) && (zpoddInfo->Load == 0)) // Drawer 1052 { 1053 DeviceSendIoctlAsynchronously(deviceExtension, IOCTL_STORAGE_EJECT_MEDIA, deviceExtension->DeviceObject); 1054 } 1055 } 1056 else 1057 { 1058 // This wake-up is caused by non-cached CDB received or a 3rd-party driver 1059 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, 1060 "DeviceEvtD0Entry: Device has left zero power state due to IO received\n" 1061 )); 1062 1063 } 1064 } 1065 } 1066 1067 DeviceEnableMainTimer(deviceExtension); 1068 } 1069 1070 return STATUS_SUCCESS; 1071 } 1072 1073 NTSTATUS 1074 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 1075 DeviceEvtD0Exit( 1076 _In_ WDFDEVICE Device, 1077 _In_ WDF_POWER_DEVICE_STATE TargetState 1078 ) 1079 /*++ 1080 1081 Routine Description: 1082 1083 This function is called when the device is entering lower powe state from D0 or it's removed. 1084 We only care about the case of device entering D3. 1085 The purpose of this function is to send SYNC CACHE command and STOP UNIT command if it's necessary. 1086 1087 Arguments: 1088 1089 Device - Handle to device object 1090 TargetState - Power state the device is entering. 1091 1092 Return Value: 1093 1094 NTSTATUS: alway STATUS_SUCCESS 1095 1096 --*/ 1097 { 1098 NTSTATUS status = STATUS_SUCCESS; 1099 PCDROM_DEVICE_EXTENSION deviceExtension = NULL; 1100 PZERO_POWER_ODD_INFO zpoddInfo = NULL; 1101 1102 PAGED_CODE (); 1103 1104 deviceExtension = DeviceGetExtension(Device); 1105 zpoddInfo = deviceExtension->ZeroPowerODDInfo; 1106 1107 // we only process the situation that the device is going into D3. 1108 if ((TargetState != WdfPowerDeviceD3) && 1109 (TargetState != WdfPowerDeviceD3Final)) 1110 { 1111 return STATUS_SUCCESS; 1112 } 1113 1114 // Stop the main timer 1115 DeviceDisableMainTimer(deviceExtension); 1116 1117 // note: do not stop CreateQueue as the create request can be handled by port driver even the device is in D3 status. 1118 1119 // If initialization was not finished or the device was removed, we cannot interact 1120 // with it device, so we have to exit 1121 if ((!deviceExtension->IsInitialized) || deviceExtension->SurpriseRemoved) 1122 { 1123 return STATUS_SUCCESS; 1124 } 1125 1126 1127 #ifdef DBG 1128 #if (WINVER >= 0x0601) 1129 // this API is introduced in Windows7 1130 { 1131 ULONG secondsRemaining = 0; 1132 BOOLEAN watchdogTimeSupported = FALSE; 1133 1134 watchdogTimeSupported = PoQueryWatchdogTime(deviceExtension->LowerPdo, &secondsRemaining); 1135 UNREFERENCED_PARAMETER(watchdogTimeSupported); 1136 } 1137 #endif 1138 #endif 1139 1140 deviceExtension->PowerDownInProgress = TRUE; 1141 1142 status = PowerContextBeginUse(deviceExtension); 1143 1144 deviceExtension->PowerContext.Options.PowerDown = TRUE; 1145 1146 // Step 1. LOCK QUEUE 1147 if (NT_SUCCESS(status) && 1148 (TargetState != WdfPowerDeviceD3Final)) 1149 { 1150 status = DeviceSendPowerDownProcessRequest(deviceExtension, NULL, NULL); 1151 1152 if (NT_SUCCESS(status)) 1153 { 1154 deviceExtension->PowerContext.Options.LockQueue = TRUE; 1155 } 1156 1157 // Ignore failure. 1158 status = STATUS_SUCCESS; 1159 } 1160 1161 deviceExtension->PowerContext.PowerChangeState.PowerDown++; 1162 1163 // Step 2. QUIESCE QUEUE 1164 if (NT_SUCCESS(status) && 1165 (TargetState != WdfPowerDeviceD3Final)) 1166 { 1167 status = DeviceSendPowerDownProcessRequest(deviceExtension, NULL, NULL); 1168 UNREFERENCED_PARAMETER(status); 1169 // We don't care about the status. 1170 status = STATUS_SUCCESS; 1171 } 1172 1173 deviceExtension->PowerContext.PowerChangeState.PowerDown++; 1174 1175 // Step 3. SYNC CACHE command should be sent to drive if the media is currently writable. 1176 if (NT_SUCCESS(status) && 1177 deviceExtension->DeviceAdditionalData.Mmc.WriteAllowed) 1178 { 1179 status = DeviceSendPowerDownProcessRequest(deviceExtension, NULL, NULL); 1180 UNREFERENCED_PARAMETER(status); 1181 status = STATUS_SUCCESS; 1182 } 1183 1184 deviceExtension->PowerContext.PowerChangeState.PowerDown++; 1185 1186 // Step 4. STOP UNIT 1187 if (NT_SUCCESS(status) && 1188 !TEST_FLAG(deviceExtension->ScanForSpecialFlags, CDROM_SPECIAL_DISABLE_SPIN_DOWN)) 1189 { 1190 status = DeviceSendPowerDownProcessRequest(deviceExtension, NULL, NULL); 1191 UNREFERENCED_PARAMETER(status); 1192 status = STATUS_SUCCESS; 1193 } 1194 1195 if (TargetState == WdfPowerDeviceD3Final) 1196 { 1197 // We're done with the power context. 1198 PowerContextEndUse(deviceExtension); 1199 } 1200 1201 // Bumping the media change count will force the file system to verify the volume when we resume 1202 SET_FLAG(deviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME); 1203 InterlockedIncrement((PLONG)&deviceExtension->MediaChangeCount); 1204 1205 // If this power down is caused by Zero Power ODD, we should mark the device as in ZPODD mode. 1206 if (zpoddInfo != NULL) 1207 { 1208 zpoddInfo->InZeroPowerState = TRUE; 1209 1210 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, 1211 "Device has entered zero power state\n" 1212 )); 1213 } 1214 1215 deviceExtension->PowerDownInProgress = FALSE; 1216 1217 return STATUS_SUCCESS; 1218 } 1219 1220 1221 VOID 1222 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 1223 DeviceEvtSurpriseRemoval( 1224 _In_ WDFDEVICE Device 1225 ) 1226 /*++ 1227 1228 Routine Description: 1229 1230 this function is called when the device is surprisely removed. 1231 Stop all IO queues so that there will be no more request being sent down. 1232 1233 Arguments: 1234 1235 Device - Handle to device object 1236 1237 Return Value: 1238 1239 None. 1240 1241 --*/ 1242 { 1243 PCDROM_DEVICE_EXTENSION deviceExtension = NULL; 1244 1245 PAGED_CODE(); 1246 1247 deviceExtension = DeviceGetExtension(Device); 1248 1249 deviceExtension->SurpriseRemoved = TRUE; 1250 1251 // Stop the main timer 1252 DeviceDisableMainTimer(deviceExtension); 1253 1254 // legacy behavior to set partition length to be 0. 1255 deviceExtension->PartitionLength.QuadPart = 0; 1256 1257 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, 1258 "Surprisely remove a WDFDEVICE %p\n", Device)); 1259 1260 return; 1261 } 1262 1263 1264 VOID 1265 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 1266 CreateQueueEvtIoDefault( 1267 _In_ WDFQUEUE Queue, 1268 _In_ WDFREQUEST Request 1269 ) 1270 /*++ 1271 1272 Routine Description: 1273 1274 this function is called when CREATE irp comes. 1275 setup FileObject context fields, so it can be used to track MCN or exclusive lock/unlock. 1276 1277 Arguments: 1278 1279 Queue - Handle to device queue 1280 1281 Request - the creation request 1282 1283 Return Value: 1284 1285 None 1286 1287 --*/ 1288 { 1289 WDFFILEOBJECT fileObject = WdfRequestGetFileObject(Request); 1290 WDFDEVICE device = WdfIoQueueGetDevice(Queue); 1291 NTSTATUS status = STATUS_SUCCESS; 1292 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device); 1293 PFILE_OBJECT_CONTEXT fileObjectContext = NULL; 1294 1295 PAGED_CODE(); 1296 1297 if (fileObject == NULL) { 1298 1299 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_QUEUE, 1300 "Error: received a file create request with file object set to NULL\n")); 1301 1302 RequestCompletion(deviceExtension, Request, STATUS_INTERNAL_ERROR, 0); 1303 return; 1304 } 1305 1306 fileObjectContext = FileObjectGetContext(fileObject); 1307 1308 // Initialize this WDFFILEOBJECT's context 1309 fileObjectContext->DeviceObject = device; 1310 fileObjectContext->FileObject = fileObject; 1311 fileObjectContext->LockCount = 0; 1312 fileObjectContext->McnDisableCount = 0; 1313 fileObjectContext->EnforceStreamingRead = FALSE; 1314 fileObjectContext->EnforceStreamingWrite = FALSE; 1315 1316 // send down the create synchronously 1317 status = DeviceSendRequestSynchronously(device, Request, FALSE); 1318 1319 // Need to complete the request in this routine. 1320 RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request)); 1321 1322 return; 1323 } 1324 1325 VOID 1326 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 1327 DeviceEvtFileClose( 1328 _In_ WDFFILEOBJECT FileObject 1329 ) 1330 /*++ 1331 1332 Routine Description: 1333 1334 this function is called when CLOSE irp comes. 1335 clean up MCN / Lock if necessary 1336 1337 Arguments: 1338 1339 FileObject - WDF file object created for the irp. 1340 1341 Return Value: 1342 1343 None 1344 1345 --*/ 1346 { 1347 NTSTATUS status = STATUS_SUCCESS; 1348 1349 PAGED_CODE(); 1350 1351 if (FileObject != NULL) 1352 { 1353 WDFDEVICE device = WdfFileObjectGetDevice(FileObject); 1354 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device); 1355 PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); 1356 PFILE_OBJECT_CONTEXT fileObjectContext = FileObjectGetContext(FileObject); 1357 1358 // cleanup locked media tray 1359 status = DeviceCleanupProtectedLocks(deviceExtension, fileObjectContext); 1360 if (!NT_SUCCESS(status)) 1361 { 1362 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, 1363 "Failed to cleanup protected locks for WDFDEVICE %p, %!STATUS!\n", device, status)); 1364 } 1365 1366 // cleanup disabled MCN 1367 status = DeviceCleanupDisableMcn(deviceExtension, fileObjectContext); 1368 if (!NT_SUCCESS(status)) 1369 { 1370 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, 1371 "Failed to disable MCN for WDFDEVICE %p, %!STATUS!\n", device, status)); 1372 } 1373 1374 // cleanup exclusive access 1375 if (EXCLUSIVE_MODE(cdData) && EXCLUSIVE_OWNER(cdData, FileObject)) 1376 { 1377 status = DeviceUnlockExclusive(deviceExtension, FileObject, FALSE); 1378 if (!NT_SUCCESS(status)) 1379 { 1380 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, 1381 "Failed to release exclusive lock for WDFDEVICE %p, %!STATUS!\n", device, status)); 1382 } 1383 } 1384 } 1385 1386 return; 1387 } 1388 1389 _IRQL_requires_max_(PASSIVE_LEVEL) 1390 NTSTATUS 1391 DeviceCleanupProtectedLocks( 1392 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1393 _In_ PFILE_OBJECT_CONTEXT FileObjectContext 1394 ) 1395 /*++ 1396 1397 Routine Description: 1398 1399 this function removes protected locks for the handle 1400 1401 Arguments: 1402 1403 DeviceExtension - device context 1404 1405 FileObject - WDF file object created for the irp. 1406 1407 Return Value: 1408 1409 NTSTATUS 1410 1411 --*/ 1412 { 1413 NTSTATUS status = STATUS_SUCCESS; 1414 1415 PAGED_CODE(); 1416 1417 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, 1418 "CleanupProtectedLocks called for WDFDEVICE %p, WDFFILEOBJECT %p, locked %d times.\n", 1419 DeviceExtension->Device, FileObjectContext->FileObject, FileObjectContext->LockCount)); 1420 1421 // Synchronize with ejection and ejection control requests. 1422 WdfWaitLockAcquire(DeviceExtension->EjectSynchronizationLock, NULL); 1423 1424 // For each secure lock on this handle decrement the secured lock count 1425 // for the FDO. Keep track of the new value. 1426 if (FileObjectContext->LockCount != 0) 1427 { 1428 DeviceExtension->ProtectedLockCount -= FileObjectContext->LockCount; 1429 FileObjectContext->LockCount = 0; 1430 1431 // If the new lock count has been dropped to zero then issue a lock 1432 // command to the device. 1433 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, 1434 "FDO secured lock count = %d " 1435 "lock count = %d\n", 1436 DeviceExtension->ProtectedLockCount, 1437 DeviceExtension->LockCount)); 1438 1439 if ((DeviceExtension->ProtectedLockCount == 0) && (DeviceExtension->LockCount == 0)) 1440 { 1441 SCSI_REQUEST_BLOCK srb = {0}; 1442 PCDB cdb = (PCDB) &(srb.Cdb); 1443 1444 srb.CdbLength = 6; 1445 1446 cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; 1447 1448 // TRUE - prevent media removal. 1449 // FALSE - allow media removal. 1450 cdb->MEDIA_REMOVAL.Prevent = FALSE; 1451 1452 // Set timeout value. 1453 srb.TimeOutValue = DeviceExtension->TimeOutValue; 1454 status = DeviceSendSrbSynchronously(DeviceExtension->Device, 1455 &srb, 1456 NULL, 1457 0, 1458 FALSE, 1459 NULL); 1460 1461 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, 1462 "Allow media removal (unlock) request to drive returned %!STATUS!\n", 1463 status)); 1464 } 1465 } 1466 1467 WdfWaitLockRelease(DeviceExtension->EjectSynchronizationLock); 1468 1469 return status; 1470 } 1471 1472 1473 _IRQL_requires_max_(APC_LEVEL) 1474 NTSTATUS 1475 DeviceCleanupDisableMcn( 1476 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1477 _In_ PFILE_OBJECT_CONTEXT FileObjectContext 1478 ) 1479 /*++ 1480 1481 Routine Description: 1482 1483 cleanup the MCN disable count for the handle 1484 1485 Arguments: 1486 1487 DeviceExtension - device context 1488 1489 FileObject - WDF file object created for the irp. 1490 1491 Return Value: 1492 1493 NTSTATUS 1494 1495 --*/ 1496 { 1497 PAGED_CODE(); 1498 1499 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, 1500 "CleanupDisableMcn called for WDFDEVICE %p, WDFFILEOBJECT %p, locked %d times.\n", 1501 DeviceExtension->Device, FileObjectContext->FileObject, FileObjectContext->McnDisableCount)); 1502 1503 // For each secure lock on this handle decrement the secured lock count 1504 // for the FDO. Keep track of the new value. 1505 while (FileObjectContext->McnDisableCount != 0) 1506 { 1507 DeviceEnableMediaChangeDetection(DeviceExtension, FileObjectContext, TRUE); 1508 } 1509 1510 return STATUS_SUCCESS; 1511 } 1512 1513 VOID 1514 NormalizeIoctl( 1515 _Inout_ PWDF_REQUEST_PARAMETERS requestParameters 1516 ) 1517 { 1518 ULONG ioctlCode; 1519 ULONG baseCode; 1520 ULONG functionCode; 1521 1522 // if this is a class driver ioctl then we need to change the base code 1523 // to IOCTL_STORAGE_BASE so that the switch statement can handle it. 1524 // 1525 // WARNING - currently the scsi class ioctl function codes are between 1526 // 0x200 & 0x300. this routine depends on that fact 1527 ioctlCode = requestParameters->Parameters.DeviceIoControl.IoControlCode; 1528 baseCode = DEVICE_TYPE_FROM_CTL_CODE(ioctlCode); 1529 functionCode = (ioctlCode & (~0xffffc003)) >> 2; 1530 1531 if ((baseCode == IOCTL_SCSI_BASE) || 1532 (baseCode == IOCTL_DISK_BASE) || 1533 (baseCode == IOCTL_TAPE_BASE) || 1534 (baseCode == IOCTL_DVD_BASE) || 1535 (baseCode == IOCTL_CDROM_BASE)) 1536 //IOCTL_STORAGE_BASE does not need to be converted. 1537 { 1538 if((functionCode >= 0x200) && (functionCode <= 0x300)) 1539 { 1540 ioctlCode = (ioctlCode & 0x0000ffff) | CTL_CODE(IOCTL_STORAGE_BASE, 0, 0, 0); 1541 1542 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, 1543 "IOCTL code recalibrate, New ioctl code is %lx\n", 1544 ioctlCode)); 1545 1546 // Set the code into request parameters, then "requestParameters" needs to be used for dispatch functions. 1547 requestParameters->Parameters.DeviceIoControl.IoControlCode = ioctlCode; 1548 } 1549 } 1550 } 1551 1552 VOID 1553 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 1554 DeviceEvtIoInCallerContext( 1555 _In_ WDFDEVICE Device, 1556 _In_ WDFREQUEST Request 1557 ) 1558 /*++ 1559 Routine Description: 1560 1561 Responds to EvtIoInCallerContext events from KMDF 1562 It calls different functions to process different type of IOCTLs. 1563 1564 Arguments: 1565 1566 Device - handle to a WDF Device object 1567 1568 Request - handle to the incoming WDF Request object 1569 1570 Return Value: 1571 1572 VOID. 1573 1574 --*/ 1575 { 1576 NTSTATUS status = STATUS_SUCCESS; 1577 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); 1578 PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); 1579 WDF_REQUEST_PARAMETERS requestParameters; 1580 1581 requestContext->DeviceExtension = deviceExtension; 1582 1583 // set the received time 1584 RequestSetReceivedTime(Request); 1585 1586 // get the request parameters 1587 WDF_REQUEST_PARAMETERS_INIT(&requestParameters); 1588 WdfRequestGetParameters(Request, &requestParameters); 1589 1590 if (requestParameters.Type == WdfRequestTypeDeviceControl) 1591 { 1592 BOOLEAN processed = FALSE; 1593 PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); 1594 PMEDIA_CHANGE_DETECTION_INFO info = deviceExtension->MediaChangeDetectionInfo; 1595 1596 if (requestParameters.Parameters.DeviceIoControl.IoControlCode != IOCTL_MCN_SYNC_FAKE_IOCTL) 1597 { 1598 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 1599 "Receiving IOCTL: %lx\n", 1600 requestParameters.Parameters.DeviceIoControl.IoControlCode)); 1601 } 1602 else 1603 { 1604 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, 1605 "Receiving IOCTL: %lx\n", 1606 requestParameters.Parameters.DeviceIoControl.IoControlCode)); 1607 } 1608 1609 // If the device is in exclusive mode, check whether the request is from 1610 // the handle that locked the device. 1611 if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request))) 1612 { 1613 BOOLEAN isBlocked = FALSE; 1614 1615 status = RequestIsIoctlBlockedByExclusiveAccess(Request, &isBlocked); 1616 UNREFERENCED_PARAMETER(status); //defensive coding, avoid PREFAST warning. 1617 1618 if (isBlocked) 1619 { 1620 if ((requestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_EVENT_NOTIFICATION) && 1621 (info != NULL) && (info->AsynchronousNotificationSupported != FALSE)) 1622 { 1623 // If AN is supported and we receive a signal but we can't send down GESN 1624 // due to exclusive lock, we should save it and fire a GESN when it's unlocked. 1625 // We just need true/false here and don't need count because we will keep sending 1626 // GESN until we deplete all events. 1627 info->ANSignalPendingDueToExclusiveLock = TRUE; 1628 } 1629 1630 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 1631 "Access Denied! Device in exclusive mode.Failing Ioctl %lx\n", 1632 requestParameters.Parameters.DeviceIoControl.IoControlCode)); 1633 RequestCompletion(deviceExtension, Request, STATUS_ACCESS_DENIED, 0); 1634 1635 return; 1636 } 1637 } 1638 1639 NormalizeIoctl(&requestParameters); 1640 1641 // 1. All requests that don't need to access device can be processed immediately 1642 if (!processed) 1643 { 1644 processed = RequestDispatchProcessDirectly(Device, Request, requestParameters); 1645 } 1646 1647 // 2. Requests that should be put in sequential queue. 1648 if (!processed) 1649 { 1650 processed = RequestDispatchToSequentialQueue(Device, Request, requestParameters); 1651 } 1652 1653 // 3. Requests that need to be processed sequentially and in caller's context. 1654 if (!processed) 1655 { 1656 processed = RequestDispatchSyncWithSequentialQueue(Device, Request, requestParameters); 1657 } 1658 1659 // 4. Special requests that needs different process in different cases. 1660 if (!processed) 1661 { 1662 processed = RequestDispatchSpecialIoctls(Device, Request, requestParameters); 1663 } 1664 1665 // 5. This is default behavior for unknown IOCTLs. To pass it to lower level. 1666 if (!processed) 1667 { 1668 processed = RequestDispatchUnknownRequests(Device, Request, requestParameters); 1669 } 1670 1671 // All requests should be processed already. 1672 NT_ASSERT(processed); 1673 UNREFERENCED_PARAMETER(processed); //defensive coding, avoid PREFAST warning. 1674 } 1675 else if (requestParameters.Type == WdfRequestTypeDeviceControlInternal) 1676 { 1677 RequestProcessInternalDeviceControl(Request, deviceExtension); 1678 } 1679 else 1680 { 1681 // Requests other than IOCTLs will be forwarded to default queue. 1682 status = WdfDeviceEnqueueRequest(Device, Request); 1683 if (!NT_SUCCESS(status)) 1684 { 1685 RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request)); 1686 } 1687 } 1688 1689 return; 1690 } 1691 1692 1693 BOOLEAN 1694 RequestDispatchProcessDirectly( 1695 _In_ WDFDEVICE Device, 1696 _In_ WDFREQUEST Request, 1697 _In_ WDF_REQUEST_PARAMETERS RequestParameters 1698 ) 1699 /*++ 1700 Routine Description: 1701 1702 These requests can be processed in a non-serialized manner, most of them don't need to access device. 1703 1704 Arguments: 1705 1706 Device - handle to a WDF Device object 1707 1708 Request - handle to the incoming WDF Request object 1709 1710 RequestParameters - request parameters 1711 1712 Return Value: 1713 1714 BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function). 1715 1716 --*/ 1717 { 1718 NTSTATUS status = STATUS_SUCCESS; 1719 BOOLEAN processed = FALSE; 1720 size_t dataLength = 0; 1721 1722 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); 1723 ULONG ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; 1724 1725 switch (ioctlCode) 1726 { 1727 1728 case IOCTL_CDROM_GET_INQUIRY_DATA: 1729 { 1730 status = RequestHandleGetInquiryData(deviceExtension, Request, RequestParameters, &dataLength); 1731 1732 processed = TRUE; 1733 break; // complete the irp 1734 } 1735 1736 case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: 1737 { 1738 status = RequestHandleGetMediaTypeEx(deviceExtension, Request, &dataLength); 1739 1740 processed = TRUE; 1741 break; // complete the irp 1742 } 1743 1744 case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: 1745 { 1746 status = RequestHandleMountQueryUniqueId(deviceExtension, Request, RequestParameters, &dataLength); 1747 1748 processed = TRUE; 1749 break; // complete the irp 1750 } 1751 1752 case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: 1753 { 1754 status = RequestHandleMountQueryDeviceName(deviceExtension, Request, RequestParameters, &dataLength); 1755 1756 processed = TRUE; 1757 break; // complete the irp 1758 } 1759 1760 case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME: 1761 { 1762 status = RequestHandleMountQuerySuggestedLinkName(deviceExtension, Request, RequestParameters, &dataLength); 1763 1764 processed = TRUE; 1765 break; // complete the irp 1766 } 1767 1768 case IOCTL_STORAGE_GET_DEVICE_NUMBER: 1769 { 1770 status = RequestHandleGetDeviceNumber(deviceExtension, Request, RequestParameters, &dataLength); 1771 1772 processed = TRUE; 1773 break; // complete the irp 1774 } 1775 1776 case IOCTL_STORAGE_GET_HOTPLUG_INFO: 1777 { 1778 status = RequestHandleGetHotPlugInfo(deviceExtension, Request, RequestParameters, &dataLength); 1779 1780 processed = TRUE; 1781 break; // complete the irp 1782 } 1783 1784 case IOCTL_STORAGE_SET_HOTPLUG_INFO: 1785 { 1786 status = RequestHandleSetHotPlugInfo(deviceExtension, Request, RequestParameters, &dataLength); 1787 1788 processed = TRUE; 1789 break; // complete the irp 1790 } 1791 1792 case IOCTL_STORAGE_EVENT_NOTIFICATION: 1793 { 1794 status = RequestHandleEventNotification(deviceExtension, Request, &RequestParameters, &dataLength); 1795 1796 processed = TRUE; 1797 break; // complete the irp 1798 } 1799 1800 #if (NTDDI_VERSION >= NTDDI_WIN8) 1801 case IOCTL_VOLUME_ONLINE: 1802 { 1803 // 1804 // Mount manager and volume manager will 1805 // follow this online with a post online 1806 // but other callers may not. In those 1807 // cases, we process this request right 1808 // away. We approximate that these other 1809 // callers are from user mode 1810 // 1811 1812 if (WdfRequestGetRequestorMode(Request) == KernelMode) 1813 { 1814 processed = TRUE; 1815 } 1816 break; 1817 } 1818 #endif 1819 1820 default: 1821 { 1822 processed = FALSE; 1823 break; 1824 } 1825 1826 } //end of switch (ioctlCode) 1827 1828 if (processed) 1829 { 1830 UCHAR currentStackLocationFlags = 0; 1831 currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request); 1832 1833 if ((status == STATUS_VERIFY_REQUIRED) && 1834 (currentStackLocationFlags & SL_OVERRIDE_VERIFY_VOLUME)) 1835 { 1836 // If the status is verified required and this request 1837 // should bypass verify required then retry the request. 1838 status = STATUS_IO_DEVICE_ERROR; 1839 UNREFERENCED_PARAMETER(status); // disables prefast warning; defensive coding... 1840 1841 processed = RequestDispatchProcessDirectly(Device, Request, RequestParameters); 1842 } 1843 else 1844 { 1845 // Complete the request after processing it. 1846 RequestCompletion(deviceExtension, Request, status, dataLength); 1847 } 1848 } 1849 1850 return processed; 1851 } 1852 1853 1854 BOOLEAN 1855 RequestDispatchToSequentialQueue( 1856 _In_ WDFDEVICE Device, 1857 _In_ WDFREQUEST Request, 1858 _In_ WDF_REQUEST_PARAMETERS RequestParameters 1859 ) 1860 /*++ 1861 Routine Description: 1862 1863 These requests can be processed in a non-serialized manner, most of them don't need to access device. 1864 1865 Arguments: 1866 1867 Device - handle to a WDF Device object 1868 1869 Request - handle to the incoming WDF Request object 1870 1871 RequestParameters - request parameters 1872 1873 Return Value: 1874 1875 BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function). 1876 1877 --*/ 1878 { 1879 NTSTATUS status = STATUS_SUCCESS; 1880 BOOLEAN processed = FALSE; 1881 size_t dataLength = 0; 1882 BOOLEAN inZeroPowerState = FALSE; 1883 1884 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); 1885 ULONG ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; 1886 PZERO_POWER_ODD_INFO zpoddInfo = deviceExtension->ZeroPowerODDInfo; 1887 1888 if ((zpoddInfo != NULL) && 1889 (zpoddInfo->InZeroPowerState != FALSE)) 1890 { 1891 inZeroPowerState = TRUE; 1892 } 1893 1894 switch (ioctlCode) 1895 { 1896 1897 case IOCTL_CDROM_RAW_READ: 1898 { 1899 status = RequestValidateRawRead(deviceExtension, Request, RequestParameters, &dataLength); 1900 1901 processed = TRUE; 1902 break; 1903 } 1904 1905 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: 1906 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX: 1907 { 1908 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 1909 "RequestDispatchToSequentialQueue: Get drive geometryEx\n")); 1910 if ( RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 1911 (ULONG)FIELD_OFFSET(DISK_GEOMETRY_EX, Data)) 1912 { 1913 status = STATUS_BUFFER_TOO_SMALL; 1914 dataLength = FIELD_OFFSET(DISK_GEOMETRY_EX, Data); 1915 } 1916 else if (inZeroPowerState != FALSE) 1917 { 1918 status = STATUS_NO_MEDIA_IN_DEVICE; 1919 } 1920 else 1921 { 1922 status = STATUS_SUCCESS; 1923 } 1924 1925 processed = TRUE; 1926 break; 1927 } 1928 1929 case IOCTL_DISK_GET_DRIVE_GEOMETRY: 1930 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: 1931 { 1932 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 1933 "RequestDispatchToSequentialQueue: Get drive geometry\n")); 1934 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 1935 sizeof(DISK_GEOMETRY)) 1936 { 1937 status = STATUS_BUFFER_TOO_SMALL; 1938 dataLength = sizeof(DISK_GEOMETRY); 1939 } 1940 else if (inZeroPowerState != FALSE) 1941 { 1942 status = STATUS_NO_MEDIA_IN_DEVICE; 1943 } 1944 else 1945 { 1946 status = STATUS_SUCCESS; 1947 } 1948 1949 processed = TRUE; 1950 break; 1951 } 1952 1953 case IOCTL_CDROM_READ_TOC_EX: 1954 { 1955 status = RequestValidateReadTocEx(deviceExtension, Request, RequestParameters, &dataLength); 1956 1957 if (inZeroPowerState != FALSE) 1958 { 1959 status = STATUS_NO_MEDIA_IN_DEVICE; 1960 } 1961 1962 processed = TRUE; 1963 break; 1964 } 1965 1966 case IOCTL_CDROM_READ_TOC: 1967 { 1968 status = RequestValidateReadToc(deviceExtension, RequestParameters, &dataLength); 1969 1970 if (inZeroPowerState != FALSE) 1971 { 1972 status = STATUS_NO_MEDIA_IN_DEVICE; 1973 } 1974 1975 processed = TRUE; 1976 break; 1977 } 1978 1979 case IOCTL_CDROM_GET_LAST_SESSION: 1980 { 1981 status = RequestValidateGetLastSession(deviceExtension, RequestParameters, &dataLength); 1982 1983 processed = TRUE; 1984 break; 1985 } 1986 1987 case IOCTL_CDROM_PLAY_AUDIO_MSF: 1988 { 1989 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 1990 "RequestDispatchToSequentialQueue: Play audio MSF\n")); 1991 1992 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 1993 sizeof(CDROM_PLAY_AUDIO_MSF)) 1994 { 1995 status = STATUS_INFO_LENGTH_MISMATCH; 1996 } 1997 else 1998 { 1999 status = STATUS_SUCCESS; 2000 } 2001 2002 processed = TRUE; 2003 break; 2004 } 2005 2006 case IOCTL_CDROM_SEEK_AUDIO_MSF: 2007 { 2008 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2009 "RequestDispatchToSequentialQueue: Seek audio MSF\n")); 2010 2011 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 2012 sizeof(CDROM_SEEK_AUDIO_MSF)) 2013 { 2014 status = STATUS_INFO_LENGTH_MISMATCH; 2015 } 2016 else 2017 { 2018 status = STATUS_SUCCESS; 2019 } 2020 2021 processed = TRUE; 2022 break; 2023 } 2024 2025 case IOCTL_CDROM_PAUSE_AUDIO: 2026 { 2027 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2028 "RequestDispatchToSequentialQueue: Pause audio\n")); 2029 2030 status = STATUS_SUCCESS; 2031 processed = TRUE; 2032 break; 2033 } 2034 2035 case IOCTL_CDROM_RESUME_AUDIO: 2036 { 2037 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2038 "RequestDispatchToSequentialQueue: Resume audio\n")); 2039 2040 status = STATUS_SUCCESS; 2041 processed = TRUE; 2042 break; 2043 } 2044 2045 case IOCTL_CDROM_READ_Q_CHANNEL: 2046 { 2047 status = RequestValidateReadQChannel(Request, RequestParameters, &dataLength); 2048 2049 processed = TRUE; 2050 break; 2051 } 2052 2053 case IOCTL_CDROM_GET_VOLUME: 2054 { 2055 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2056 "RequestDispatchToSequentialQueue: Get volume control\n")); 2057 2058 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 2059 sizeof(VOLUME_CONTROL)) 2060 { 2061 status = STATUS_BUFFER_TOO_SMALL; 2062 dataLength = sizeof(VOLUME_CONTROL); 2063 } 2064 else 2065 { 2066 status = STATUS_SUCCESS; 2067 } 2068 2069 processed = TRUE; 2070 break; 2071 } 2072 2073 case IOCTL_CDROM_SET_VOLUME: 2074 { 2075 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2076 "RequestDispatchToSequentialQueue: Set volume control\n")); 2077 2078 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 2079 sizeof(VOLUME_CONTROL)) 2080 { 2081 status = STATUS_INFO_LENGTH_MISMATCH; 2082 } 2083 else 2084 { 2085 status = STATUS_SUCCESS; 2086 } 2087 2088 processed = TRUE; 2089 break; 2090 } 2091 2092 case IOCTL_CDROM_STOP_AUDIO: 2093 { 2094 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2095 "RequestDispatchToSequentialQueue: Stop audio\n")); 2096 2097 status = STATUS_SUCCESS; 2098 processed = TRUE; 2099 break; 2100 } 2101 2102 case IOCTL_STORAGE_CHECK_VERIFY: 2103 case IOCTL_STORAGE_CHECK_VERIFY2: 2104 { 2105 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2106 "RequestDispatchToSequentialQueue: [%p] Check Verify\n", Request)); 2107 2108 // Following check will let the condition "OutputBufferLength == 0" pass. 2109 // Since it's legacy behavior in classpnp, we need to keep it. 2110 if ((RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > 0) && 2111 (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))) 2112 { 2113 status = STATUS_BUFFER_TOO_SMALL; 2114 dataLength = sizeof(ULONG); 2115 } 2116 else if (inZeroPowerState != FALSE) 2117 { 2118 status = STATUS_NO_MEDIA_IN_DEVICE; 2119 } 2120 else 2121 { 2122 status = STATUS_SUCCESS; 2123 } 2124 2125 processed = TRUE; 2126 break; 2127 } 2128 2129 case IOCTL_DVD_GET_REGION: 2130 { 2131 // validation will be done when process it. 2132 status = STATUS_SUCCESS; 2133 processed = TRUE; 2134 break; 2135 } 2136 2137 case IOCTL_DVD_READ_STRUCTURE: 2138 { 2139 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2140 "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_READ_STRUCTURE\n", Request)); 2141 2142 status = RequestValidateDvdReadStructure(deviceExtension, RequestParameters, &dataLength); 2143 2144 processed = TRUE; 2145 break; 2146 } 2147 2148 case IOCTL_DVD_READ_KEY: 2149 { 2150 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2151 "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_READ_KEY\n", Request)); 2152 2153 status = RequestValidateDvdReadKey(deviceExtension, Request, RequestParameters, &dataLength); 2154 2155 processed = TRUE; 2156 break; 2157 } 2158 2159 case IOCTL_DVD_START_SESSION: 2160 { 2161 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2162 "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_START_SESSION\n", Request)); 2163 2164 status = RequestValidateDvdStartSession(deviceExtension, RequestParameters, &dataLength); 2165 2166 processed = TRUE; 2167 break; 2168 } 2169 2170 case IOCTL_DVD_SEND_KEY: 2171 case IOCTL_DVD_SEND_KEY2: 2172 { 2173 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2174 "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_SEND_KEY\n", Request)); 2175 2176 status = RequestValidateDvdSendKey(deviceExtension, Request, RequestParameters, &dataLength); 2177 2178 processed = TRUE; 2179 break; 2180 } 2181 2182 case IOCTL_STORAGE_SET_READ_AHEAD: 2183 { 2184 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2185 "RequestDispatchToSequentialQueue: [%p] SetReadAhead\n", Request)); 2186 2187 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 2188 sizeof(STORAGE_SET_READ_AHEAD)) 2189 { 2190 status = STATUS_INVALID_PARAMETER; 2191 } 2192 else 2193 { 2194 status = STATUS_SUCCESS; 2195 } 2196 2197 processed = TRUE; 2198 break; 2199 } 2200 2201 case IOCTL_DISK_IS_WRITABLE: 2202 { 2203 status = STATUS_SUCCESS; 2204 2205 processed = TRUE; 2206 break; 2207 } 2208 2209 case IOCTL_DISK_GET_DRIVE_LAYOUT: 2210 { 2211 ULONG requiredSize = 0; 2212 2213 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2214 "RequestDispatchToSequentialQueue: Get drive layout\n")); 2215 2216 requiredSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[1]); 2217 2218 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 2219 requiredSize) 2220 { 2221 status = STATUS_BUFFER_TOO_SMALL; 2222 dataLength = requiredSize; 2223 } 2224 else 2225 { 2226 status = STATUS_SUCCESS; 2227 } 2228 2229 processed = TRUE; 2230 break; 2231 } 2232 2233 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: 2234 { 2235 ULONG requiredSize = 0; 2236 2237 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2238 "RequestDispatchToSequentialQueue: Get drive layoutEx\n")); 2239 2240 requiredSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[1]); 2241 2242 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 2243 requiredSize) 2244 { 2245 status = STATUS_BUFFER_TOO_SMALL; 2246 dataLength = requiredSize; 2247 } 2248 else 2249 { 2250 status = STATUS_SUCCESS; 2251 } 2252 2253 processed = TRUE; 2254 break; 2255 } 2256 2257 case IOCTL_DISK_GET_PARTITION_INFO: 2258 { 2259 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2260 "RequestDispatchToSequentialQueue: Get Partition Info\n")); 2261 2262 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 2263 sizeof(PARTITION_INFORMATION)) 2264 { 2265 status = STATUS_BUFFER_TOO_SMALL; 2266 dataLength = sizeof(PARTITION_INFORMATION); 2267 } 2268 else 2269 { 2270 status = STATUS_SUCCESS; 2271 } 2272 2273 processed = TRUE; 2274 break; 2275 } 2276 2277 case IOCTL_DISK_GET_PARTITION_INFO_EX: 2278 { 2279 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2280 "RequestDispatchToSequentialQueue: Get Partition InfoEx\n")); 2281 2282 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 2283 sizeof(PARTITION_INFORMATION_EX)) 2284 { 2285 status = STATUS_BUFFER_TOO_SMALL; 2286 dataLength = sizeof(PARTITION_INFORMATION_EX); 2287 } 2288 else 2289 { 2290 status = STATUS_SUCCESS; 2291 } 2292 2293 processed = TRUE; 2294 break; 2295 } 2296 2297 case IOCTL_DISK_VERIFY: 2298 { 2299 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2300 "RequestDispatchToSequentialQueue: IOCTL_DISK_VERIFY to device %p through request %p\n", 2301 Device, 2302 Request)); 2303 2304 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 2305 sizeof(VERIFY_INFORMATION)) 2306 { 2307 status = STATUS_INVALID_PARAMETER; 2308 } 2309 else 2310 { 2311 status = STATUS_SUCCESS; 2312 } 2313 2314 processed = TRUE; 2315 break; 2316 } 2317 2318 case IOCTL_DISK_GET_LENGTH_INFO: 2319 { 2320 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2321 "RequestDispatchToSequentialQueue: Disk Get Length InfoEx\n")); 2322 2323 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < 2324 sizeof(GET_LENGTH_INFORMATION)) 2325 { 2326 status = STATUS_BUFFER_TOO_SMALL; 2327 dataLength = sizeof(GET_LENGTH_INFORMATION); 2328 } 2329 else if (inZeroPowerState != FALSE) 2330 { 2331 status = STATUS_NO_MEDIA_IN_DEVICE; 2332 } 2333 else 2334 { 2335 status = STATUS_SUCCESS; 2336 } 2337 2338 processed = TRUE; 2339 break; 2340 } 2341 2342 case IOCTL_CDROM_GET_CONFIGURATION: 2343 { 2344 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2345 "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_GET_CONFIGURATION\n", Request)); 2346 2347 status = RequestValidateGetConfiguration(deviceExtension, Request, RequestParameters, &dataLength); 2348 2349 processed = TRUE; 2350 break; 2351 } 2352 2353 case IOCTL_CDROM_SET_SPEED: 2354 { 2355 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2356 "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_SET_SPEED\n", Request)); 2357 2358 status = RequestValidateSetSpeed(deviceExtension, Request, RequestParameters, &dataLength); 2359 2360 processed = TRUE; 2361 break; 2362 } 2363 2364 case IOCTL_DVD_END_SESSION: 2365 { 2366 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2367 "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_END_SESSION\n", Request)); 2368 2369 status = RequestValidateDvdEndSession(deviceExtension, Request, RequestParameters, &dataLength); 2370 2371 processed = TRUE; 2372 break; 2373 } 2374 2375 case IOCTL_AACS_END_SESSION: 2376 { 2377 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2378 "RequestDispatchToSequentialQueue: [%p] IOCTL_AACS_END_SESSION\n", Request)); 2379 2380 status = RequestValidateAacsEndSession(deviceExtension, Request, RequestParameters, &dataLength); 2381 2382 processed = TRUE; 2383 break; 2384 } 2385 2386 case IOCTL_AACS_READ_MEDIA_KEY_BLOCK: 2387 { 2388 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 2389 "AACS: Querying full MKB with bufferSize of %x bytes\n", 2390 (int)RequestParameters.Parameters.DeviceIoControl.OutputBufferLength 2391 )); 2392 2393 status = RequestValidateAacsReadMediaKeyBlock(deviceExtension, Request, RequestParameters, &dataLength); 2394 2395 processed = TRUE; 2396 break; 2397 } 2398 2399 case IOCTL_AACS_START_SESSION: 2400 { 2401 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 2402 "AACS: Requesting AGID\n" 2403 )); 2404 2405 status = RequestValidateAacsStartSession(deviceExtension, RequestParameters, &dataLength); 2406 2407 processed = TRUE; 2408 break; 2409 } 2410 2411 case IOCTL_AACS_SEND_CERTIFICATE: 2412 { 2413 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 2414 "AACS: Sending host certificate to drive\n" 2415 )); 2416 2417 status = RequestValidateAacsSendCertificate(deviceExtension, Request, RequestParameters, &dataLength); 2418 2419 processed = TRUE; 2420 break; 2421 } 2422 2423 case IOCTL_AACS_GET_CERTIFICATE: 2424 { 2425 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 2426 "AACS: Querying drive certificate\n" 2427 )); 2428 2429 status = RequestValidateAacsGetCertificate(deviceExtension, Request, RequestParameters, &dataLength); 2430 2431 processed = TRUE; 2432 break; 2433 } 2434 2435 case IOCTL_AACS_GET_CHALLENGE_KEY: 2436 { 2437 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 2438 "AACS: Querying drive challenge key\n" 2439 )); 2440 2441 status = RequestValidateAacsGetChallengeKey(deviceExtension, Request, RequestParameters, &dataLength); 2442 2443 processed = TRUE; 2444 break; 2445 } 2446 2447 case IOCTL_AACS_SEND_CHALLENGE_KEY: 2448 { 2449 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 2450 "AACS: Sending drive challenge key\n" 2451 )); 2452 2453 status = RequestValidateAacsSendChallengeKey(deviceExtension, Request, RequestParameters, &dataLength); 2454 2455 processed = TRUE; 2456 break; 2457 } 2458 2459 case IOCTL_AACS_READ_VOLUME_ID: 2460 { 2461 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 2462 "AACS: Reading volume ID\n" 2463 )); 2464 2465 status = RequestValidateAacsReadVolumeId(deviceExtension, Request, RequestParameters, &dataLength); 2466 2467 processed = TRUE; 2468 break; 2469 } 2470 2471 case IOCTL_AACS_READ_SERIAL_NUMBER: 2472 { 2473 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 2474 "AACS: Reading Serial Number\n" 2475 )); 2476 2477 status = RequestValidateAacsReadSerialNumber(deviceExtension, Request, RequestParameters, &dataLength); 2478 2479 processed = TRUE; 2480 break; 2481 } 2482 2483 case IOCTL_AACS_READ_MEDIA_ID: 2484 { 2485 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 2486 "AACS: Reading media ID\n" 2487 )); 2488 2489 status = RequestValidateAacsReadMediaId(deviceExtension, Request, RequestParameters, &dataLength); 2490 2491 processed = TRUE; 2492 break; 2493 } 2494 2495 case IOCTL_AACS_READ_BINDING_NONCE: 2496 case IOCTL_AACS_GENERATE_BINDING_NONCE: 2497 { 2498 if (ioctlCode == IOCTL_AACS_GENERATE_BINDING_NONCE) 2499 { 2500 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 2501 "AACS: Generating new binding nonce\n" 2502 )); 2503 } 2504 else 2505 { 2506 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 2507 "AACS: Reading existing binding nonce\n" 2508 )); 2509 } 2510 2511 status = RequestValidateAacsBindingNonce(deviceExtension, Request, RequestParameters, &dataLength); 2512 2513 processed = TRUE; 2514 break; 2515 } 2516 2517 case IOCTL_CDROM_ENABLE_STREAMING: 2518 { 2519 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2520 "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_ENABLE_STREAMING\n", Request)); 2521 2522 status = RequestValidateEnableStreaming(Request, RequestParameters, &dataLength); 2523 2524 processed = TRUE; 2525 break; 2526 } 2527 2528 case IOCTL_CDROM_SEND_OPC_INFORMATION: 2529 { 2530 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2531 "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_SEND_OPC_INFORMATION\n", Request)); 2532 2533 status = RequestValidateSendOpcInformation(Request, RequestParameters, &dataLength); 2534 2535 processed = TRUE; 2536 break; 2537 } 2538 2539 case IOCTL_CDROM_GET_PERFORMANCE: 2540 { 2541 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 2542 "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_GET_PERFORMANCE\n", Request)); 2543 2544 status = RequestValidateGetPerformance(Request, RequestParameters, &dataLength); 2545 2546 processed = TRUE; 2547 break; 2548 } 2549 2550 case IOCTL_STORAGE_MEDIA_REMOVAL: 2551 case IOCTL_STORAGE_EJECTION_CONTROL: 2552 { 2553 if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 2554 sizeof(PREVENT_MEDIA_REMOVAL)) 2555 { 2556 status = STATUS_INFO_LENGTH_MISMATCH; 2557 } 2558 else 2559 { 2560 status = STATUS_SUCCESS; 2561 } 2562 2563 processed = TRUE; 2564 break; // complete the irp 2565 } 2566 2567 case IOCTL_STORAGE_MCN_CONTROL: 2568 { 2569 if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength < 2570 sizeof(PREVENT_MEDIA_REMOVAL)) 2571 { 2572 status = STATUS_INFO_LENGTH_MISMATCH; 2573 } 2574 else 2575 { 2576 status = STATUS_SUCCESS; 2577 } 2578 2579 processed = TRUE; 2580 break; // complete the irp 2581 } 2582 2583 case IOCTL_STORAGE_RESERVE: 2584 case IOCTL_STORAGE_RELEASE: 2585 { 2586 // there is no validate check currently. 2587 status = STATUS_SUCCESS; 2588 processed = TRUE; 2589 break; 2590 } 2591 2592 case IOCTL_STORAGE_PERSISTENT_RESERVE_IN: 2593 case IOCTL_STORAGE_PERSISTENT_RESERVE_OUT: 2594 { 2595 status = RequestValidatePersistentReserve(deviceExtension, Request, RequestParameters, &dataLength); 2596 2597 processed = TRUE; 2598 break; 2599 } 2600 2601 case IOCTL_STORAGE_EJECT_MEDIA: 2602 case IOCTL_STORAGE_LOAD_MEDIA: 2603 case IOCTL_STORAGE_LOAD_MEDIA2: 2604 { 2605 status = STATUS_SUCCESS; 2606 2607 processed = TRUE; 2608 break; // complete the irp 2609 } 2610 2611 case IOCTL_STORAGE_FIND_NEW_DEVICES: 2612 { 2613 // process it. 2614 IoInvalidateDeviceRelations(deviceExtension->LowerPdo, BusRelations); 2615 2616 status = STATUS_SUCCESS; 2617 2618 processed = TRUE; 2619 break; // complete the irp 2620 } 2621 2622 case IOCTL_STORAGE_READ_CAPACITY: 2623 { 2624 if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_READ_CAPACITY)) 2625 { 2626 dataLength = sizeof(STORAGE_READ_CAPACITY); 2627 status = STATUS_BUFFER_TOO_SMALL; 2628 } 2629 else if (inZeroPowerState != FALSE) 2630 { 2631 status = STATUS_NO_MEDIA_IN_DEVICE; 2632 } 2633 else 2634 { 2635 status = STATUS_SUCCESS; 2636 } 2637 2638 processed = TRUE; 2639 break; // complete the irp 2640 } 2641 2642 case IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT: 2643 { 2644 // for disk.sys only in original classpnp 2645 status = STATUS_NOT_SUPPORTED; 2646 2647 processed = TRUE; 2648 break; // complete the irp 2649 } 2650 2651 #if (NTDDI_VERSION >= NTDDI_WIN8) 2652 case IOCTL_DISK_ARE_VOLUMES_READY: 2653 { 2654 // this request doesn't access device at all, so seemingly it can be processed 2655 // directly; however, in case volume online is not received, we will need to 2656 // park these requests in a queue, and the only way a request can be queued is 2657 // if the request came out of another queue. 2658 status = STATUS_SUCCESS; 2659 2660 processed = TRUE; 2661 break; 2662 } 2663 2664 case IOCTL_VOLUME_ONLINE: 2665 case IOCTL_VOLUME_POST_ONLINE: 2666 { 2667 status = STATUS_SUCCESS; 2668 2669 processed = TRUE; 2670 break; 2671 } 2672 #endif 2673 2674 default: 2675 { 2676 processed = FALSE; 2677 break; 2678 } 2679 } //end of switch (ioctlCode) 2680 2681 if (processed) 2682 { 2683 UCHAR currentStackLocationFlags = 0; 2684 currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request); 2685 2686 if ((status == STATUS_VERIFY_REQUIRED) && 2687 (currentStackLocationFlags & SL_OVERRIDE_VERIFY_VOLUME)) 2688 { 2689 // If the status is verified required and this request 2690 // should bypass verify required then retry the request. 2691 status = STATUS_IO_DEVICE_ERROR; 2692 UNREFERENCED_PARAMETER(status); // disables prefast warning; defensive coding... 2693 2694 processed = RequestDispatchToSequentialQueue(Device, Request, RequestParameters); 2695 } 2696 else 2697 { 2698 if (NT_SUCCESS(status)) 2699 { 2700 // Forward the request to serialized queue. 2701 status = WdfDeviceEnqueueRequest(Device, Request); 2702 } 2703 2704 if (!NT_SUCCESS(status)) 2705 { 2706 // Validation failed / forward failed, complete the request. 2707 RequestCompletion(deviceExtension, Request, status, dataLength); 2708 } 2709 } 2710 } 2711 2712 return processed; 2713 } 2714 2715 2716 BOOLEAN 2717 RequestDispatchSyncWithSequentialQueue( 2718 _In_ WDFDEVICE Device, 2719 _In_ WDFREQUEST Request, 2720 _In_ WDF_REQUEST_PARAMETERS RequestParameters 2721 ) 2722 /*++ 2723 Routine Description: 2724 2725 These requests need to stay in caller's context and be processed in serialized manner. 2726 2727 Arguments: 2728 2729 Device - handle to a WDF Device object 2730 2731 Request - handle to the incoming WDF Request object 2732 2733 RequestParameters - request parameters 2734 2735 Return Value: 2736 2737 BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function). 2738 2739 --*/ 2740 { 2741 NTSTATUS status = STATUS_SUCCESS; 2742 BOOLEAN processed = FALSE; 2743 size_t dataLength = 0; 2744 2745 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); 2746 ULONG ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; 2747 2748 switch (ioctlCode) 2749 { 2750 2751 case IOCTL_CDROM_EXCLUSIVE_ACCESS: 2752 { 2753 //1. Validate 2754 status = RequestValidateExclusiveAccess(Request, RequestParameters, &dataLength); 2755 2756 //2. keep the request in serialized manner and stay in user's context. 2757 if (NT_SUCCESS(status)) 2758 { 2759 PCDROM_EXCLUSIVE_ACCESS exclusiveAccess = NULL; 2760 2761 status = WdfRequestRetrieveInputBuffer(Request, 2762 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 2763 &exclusiveAccess, 2764 NULL); 2765 2766 if (NT_SUCCESS(status)) 2767 { 2768 // do not need to check "status" as it passed validation and cannot fail in WdfRequestRetrieveInputBuffer() 2769 switch (exclusiveAccess->RequestType) 2770 { 2771 2772 case ExclusiveAccessQueryState: 2773 { 2774 status = RequestSetContextFields(Request, RequestHandleExclusiveAccessQueryLockState); 2775 break; 2776 } 2777 2778 case ExclusiveAccessLockDevice: 2779 { 2780 status = RequestSetContextFields(Request, RequestHandleExclusiveAccessLockDevice); 2781 break; 2782 } 2783 2784 case ExclusiveAccessUnlockDevice: 2785 { 2786 status = RequestSetContextFields(Request, RequestHandleExclusiveAccessUnlockDevice); 2787 break; 2788 } 2789 default: 2790 { 2791 // already valicated in RequestValidateExclusiveAccess() 2792 NT_ASSERT(FALSE); 2793 break; 2794 } 2795 } 2796 } 2797 2798 if (NT_SUCCESS(status)) 2799 { 2800 // now, put the special synchronization information into the context 2801 status = RequestSynchronizeProcessWithSerialQueue(Device, Request); 2802 2803 // "status" is used for debugging in above statement, reset to success to avoid further work in this function. 2804 status = STATUS_SUCCESS; 2805 } 2806 } 2807 2808 processed = TRUE; 2809 break; // complete the irp 2810 } 2811 2812 default: 2813 { 2814 processed = FALSE; 2815 break; 2816 } 2817 } //end of switch (ioctlCode) 2818 2819 // Following process is only valid if the request is not really processed. (failed in validation) 2820 if (processed && !NT_SUCCESS(status)) 2821 { 2822 UCHAR currentStackLocationFlags = 0; 2823 currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request); 2824 2825 if ((status == STATUS_VERIFY_REQUIRED) && 2826 (currentStackLocationFlags & SL_OVERRIDE_VERIFY_VOLUME)) 2827 { 2828 // 2829 // If the status is verified required and this request 2830 // should bypass verify required then retry the request. 2831 // 2832 status = STATUS_IO_DEVICE_ERROR; 2833 UNREFERENCED_PARAMETER(status); // disables prefast warning; defensive coding... 2834 2835 processed = RequestDispatchSyncWithSequentialQueue(Device, Request, RequestParameters); 2836 } 2837 else 2838 { 2839 // Validation failed / forward failed, complete the request. 2840 RequestCompletion(deviceExtension, Request, status, dataLength); 2841 } 2842 } 2843 2844 return processed; 2845 } 2846 2847 2848 BOOLEAN 2849 RequestDispatchSpecialIoctls( 2850 _In_ WDFDEVICE Device, 2851 _In_ WDFREQUEST Request, 2852 _In_ WDF_REQUEST_PARAMETERS RequestParameters 2853 ) 2854 /*++ 2855 Routine Description: 2856 2857 These requests need to be processed in different manner according to input parameters 2858 2859 Arguments: 2860 2861 Device - handle to a WDF Device object 2862 2863 Request - handle to the incoming WDF Request object 2864 2865 RequestParameters - request parameters 2866 2867 Return Value: 2868 2869 BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function). 2870 2871 --*/ 2872 { 2873 NTSTATUS status = STATUS_SUCCESS; 2874 BOOLEAN processed = FALSE; 2875 size_t dataLength = 0; 2876 BOOLEAN requestCompleted = FALSE; 2877 2878 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); 2879 PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); 2880 ULONG ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; 2881 2882 switch (ioctlCode) 2883 { 2884 case IOCTL_SCSI_PASS_THROUGH: 2885 case IOCTL_SCSI_PASS_THROUGH_DIRECT: 2886 case IOCTL_SCSI_PASS_THROUGH_EX: 2887 case IOCTL_SCSI_PASS_THROUGH_DIRECT_EX: 2888 { 2889 // SPTI is considered special case as we need to set the MinorFunction before pass to low level. 2890 2891 #if defined (_WIN64) 2892 if (WdfRequestIsFrom32BitProcess(Request)) 2893 { 2894 if ((ioctlCode == IOCTL_SCSI_PASS_THROUGH) || (ioctlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)) 2895 { 2896 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH32)) 2897 { 2898 status = STATUS_INVALID_PARAMETER; 2899 } 2900 } 2901 else 2902 { 2903 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH32_EX)) 2904 { 2905 status = STATUS_INVALID_PARAMETER; 2906 } 2907 } 2908 } 2909 else 2910 #endif 2911 { 2912 if ((ioctlCode == IOCTL_SCSI_PASS_THROUGH) || (ioctlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)) 2913 { 2914 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH)) 2915 { 2916 status = STATUS_INVALID_PARAMETER; 2917 } 2918 } 2919 else 2920 { 2921 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH_EX)) 2922 { 2923 status = STATUS_INVALID_PARAMETER; 2924 } 2925 } 2926 } 2927 2928 if (!NT_SUCCESS(status)) 2929 { 2930 // validation failed. 2931 RequestCompletion(deviceExtension, Request, status, dataLength); 2932 } 2933 else 2934 { 2935 // keep the request in serialized manner and stay in user's context. 2936 status = RequestSetContextFields(Request, RequestHandleScsiPassThrough); 2937 2938 if (NT_SUCCESS(status)) 2939 { 2940 status = RequestSynchronizeProcessWithSerialQueue(Device, Request); 2941 } 2942 else 2943 { 2944 RequestCompletion(deviceExtension, Request, status, 0); 2945 } 2946 } 2947 2948 requestCompleted = TRUE; 2949 processed = TRUE; 2950 break; 2951 } 2952 2953 case IOCTL_STORAGE_QUERY_PROPERTY: 2954 { 2955 if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_PROPERTY_QUERY)) 2956 { 2957 status = STATUS_INFO_LENGTH_MISMATCH; 2958 } 2959 else 2960 { 2961 PSTORAGE_PROPERTY_QUERY inputBuffer = NULL; 2962 2963 status = WdfRequestRetrieveInputBuffer(Request, 2964 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 2965 &inputBuffer, 2966 NULL); 2967 2968 if (NT_SUCCESS(status)) 2969 { 2970 if (!EXCLUSIVE_MODE(cdData) || // not locked 2971 EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request)) || // request is from lock owner 2972 (inputBuffer->QueryType == PropertyExistsQuery)) // request not access device 2973 { 2974 if (inputBuffer->PropertyId == StorageDeviceUniqueIdProperty) 2975 { 2976 // previously handled in classpnp 2977 // keep the request in serialized manner and stay in user's context. 2978 status = RequestSetContextFields(Request, RequestHandleQueryPropertyDeviceUniqueId); 2979 2980 if (NT_SUCCESS(status)) 2981 { 2982 status = RequestSynchronizeProcessWithSerialQueue(Device, Request); 2983 // remeber that the request has been completed. 2984 requestCompleted = TRUE; 2985 } 2986 } 2987 else if (inputBuffer->PropertyId == StorageDeviceWriteCacheProperty) 2988 { 2989 // previously handled in classpnp 2990 // keep the request in serialized manner and stay in user's context. 2991 status = RequestSetContextFields(Request, RequestHandleQueryPropertyWriteCache); 2992 2993 if (NT_SUCCESS(status)) 2994 { 2995 status = RequestSynchronizeProcessWithSerialQueue(Device, Request); 2996 // remeber that the request has been completed. 2997 requestCompleted = TRUE; 2998 } 2999 } 3000 else 3001 { 3002 // Pass to port driver for handling 3003 RequestDispatchUnknownRequests(Device, Request, RequestParameters); 3004 3005 // remeber that the request has been completed. 3006 requestCompleted = TRUE; 3007 } 3008 } 3009 else 3010 { 3011 // If cached data exists, return cached data. Otherwise, fail the request. 3012 if ((inputBuffer->QueryType == PropertyStandardQuery) && 3013 ((inputBuffer->PropertyId == StorageDeviceProperty) || (inputBuffer->PropertyId == StorageAdapterProperty)) ) 3014 { 3015 status = RequestHandleQueryPropertyRetrieveCachedData(deviceExtension, Request, RequestParameters, &dataLength); 3016 } 3017 else 3018 { 3019 status = STATUS_ACCESS_DENIED; 3020 } 3021 } 3022 } 3023 } 3024 3025 processed = TRUE; 3026 break; 3027 } 3028 3029 // this IOCTL is a fake one, used for MCN process sync-ed with serial queue. 3030 case IOCTL_MCN_SYNC_FAKE_IOCTL: 3031 { 3032 PIRP irp = WdfRequestWdmGetIrp(Request); 3033 3034 if ((deviceExtension->MediaChangeDetectionInfo != NULL) && 3035 (irp == deviceExtension->MediaChangeDetectionInfo->MediaChangeSyncIrp) && 3036 (WdfRequestGetRequestorMode(Request) == KernelMode) && 3037 (RequestParameters.Parameters.Others.Arg1 == RequestSetupMcnSyncIrp) && 3038 (RequestParameters.Parameters.Others.Arg2 == RequestSetupMcnSyncIrp) && 3039 (RequestParameters.Parameters.Others.Arg4 == RequestSetupMcnSyncIrp)) 3040 { 3041 // This is the requset we use to sync Media Change Detection with sequential queue. 3042 status = WdfDeviceEnqueueRequest(Device, Request); 3043 3044 if (!NT_SUCCESS(status)) 3045 { 3046 RequestCompletion(deviceExtension, Request, status, dataLength); 3047 } 3048 3049 requestCompleted = TRUE; 3050 processed = TRUE; 3051 } 3052 else 3053 { 3054 // process as an unknown request. 3055 processed = FALSE; 3056 } 3057 break; 3058 } 3059 3060 default: 3061 { 3062 processed = FALSE; 3063 break; 3064 } 3065 } //end of switch (ioctlCode) 3066 3067 if (processed && !requestCompleted) 3068 { 3069 UCHAR currentStackLocationFlags = 0; 3070 currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request); 3071 3072 if ((status == STATUS_VERIFY_REQUIRED) && 3073 (currentStackLocationFlags & SL_OVERRIDE_VERIFY_VOLUME)) 3074 { 3075 // If the status is verified required and this request 3076 // should bypass verify required then retry the request. 3077 status = STATUS_IO_DEVICE_ERROR; 3078 UNREFERENCED_PARAMETER(status); // disables prefast warning; defensive coding... 3079 3080 processed = RequestDispatchSpecialIoctls(Device, Request, RequestParameters); 3081 } 3082 else 3083 { 3084 RequestCompletion(deviceExtension, Request, status, dataLength); 3085 } 3086 } 3087 3088 return processed; 3089 } 3090 3091 3092 BOOLEAN 3093 RequestDispatchUnknownRequests( 3094 _In_ WDFDEVICE Device, 3095 _In_ WDFREQUEST Request, 3096 _In_ WDF_REQUEST_PARAMETERS RequestParameters 3097 ) 3098 /*++ 3099 Routine Description: 3100 3101 All unknown requests will be pass to lower level driver. 3102 If IRQL is PASSIVE_LEVEL, the request will be serialized; 3103 Otherwise, it'll be sent and forget. 3104 3105 Arguments: 3106 3107 Device - handle to a WDF Device object 3108 3109 Request - handle to the incoming WDF Request object 3110 3111 RequestParameters - request parameters 3112 3113 Return Value: 3114 3115 BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function). 3116 3117 --*/ 3118 { 3119 NTSTATUS status = STATUS_UNSUCCESSFUL; 3120 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); 3121 3122 ULONG baseCode = DEVICE_TYPE_FROM_CTL_CODE(RequestParameters.Parameters.DeviceIoControl.IoControlCode); 3123 3124 if ((KeGetCurrentIrql() != PASSIVE_LEVEL) || 3125 (baseCode == FILE_DEVICE_ACPI)) 3126 { 3127 // 1. When IRQL is higher than PASSIVE_LEVEL, 3128 // 2. ataport sends IOCTL_ACPI_ASYNC_EVAL_METHOD before queue starts, 3129 // send request directly to lower driver. 3130 status = RequestHandleUnknownIoctl(Device, Request); 3131 } 3132 else 3133 { 3134 // keep the request in serialized manner and stay in user's context. 3135 status = RequestSetContextFields(Request, RequestHandleUnknownIoctl); 3136 3137 if (NT_SUCCESS(status)) 3138 { 3139 status = RequestSynchronizeProcessWithSerialQueue(Device, Request); 3140 } 3141 else 3142 { 3143 RequestCompletion(deviceExtension, Request, status, 0); 3144 } 3145 } 3146 3147 UNREFERENCED_PARAMETER(status); //defensive coding, avoid PREFAST warning. 3148 3149 // All unknown IOCTLs are processed in this function. 3150 return TRUE; //processed 3151 } 3152 3153 VOID 3154 RequestProcessInternalDeviceControl( 3155 _In_ WDFREQUEST Request, 3156 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension 3157 ) 3158 /*++ 3159 Routine Description: 3160 3161 all internal IOCTL will be send to lower driver asynchronously. 3162 3163 Arguments: 3164 3165 Request - handle to the incoming WDF Request object 3166 DeviceExtension - device extension structure 3167 3168 Return Value: 3169 3170 None 3171 3172 --*/ 3173 { 3174 NTSTATUS status = STATUS_SUCCESS; 3175 PIRP irp = NULL; 3176 PIO_STACK_LOCATION irpStack = NULL; 3177 PIO_STACK_LOCATION nextStack = NULL; 3178 BOOLEAN requestSent = FALSE; 3179 3180 irp = WdfRequestWdmGetIrp(Request); 3181 irpStack = IoGetCurrentIrpStackLocation(irp); 3182 nextStack = IoGetNextIrpStackLocation(irp); 3183 3184 // Set the parameters in the next stack location. 3185 nextStack->Parameters.Scsi.Srb = irpStack->Parameters.Scsi.Srb; 3186 nextStack->MajorFunction = IRP_MJ_SCSI; 3187 nextStack->MinorFunction = IRP_MN_SCSI_CLASS; 3188 3189 WdfRequestSetCompletionRoutine(Request, RequestDummyCompletionRoutine, NULL); 3190 3191 status = RequestSend(DeviceExtension, 3192 Request, 3193 DeviceExtension->IoTarget, 3194 0, 3195 &requestSent); 3196 3197 // send the request straight down (asynchronously) 3198 if (!requestSent) 3199 { 3200 // fail the request 3201 RequestCompletion(DeviceExtension, Request, status, WdfRequestGetInformation(Request)); 3202 } 3203 3204 return; 3205 } 3206 3207 3208 3209 // 3210 // Serial I/O Queue Event callbacks 3211 // 3212 3213 VOID 3214 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 3215 SequentialQueueEvtIoReadWrite( 3216 _In_ WDFQUEUE Queue, 3217 _In_ WDFREQUEST Request, 3218 _In_ size_t Length 3219 ) 3220 /*++ 3221 Routine Description: 3222 3223 validate and process read/write request. 3224 3225 Arguments: 3226 3227 Queue - parallel queue itself 3228 3229 Request - handle to the incoming WDF Request object 3230 3231 Length - read / write lenght 3232 3233 Return Value: 3234 3235 None 3236 3237 --*/ 3238 { 3239 NTSTATUS status = STATUS_SUCCESS; 3240 WDFDEVICE device = WdfIoQueueGetDevice(Queue); 3241 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device); 3242 WDF_REQUEST_PARAMETERS requestParameters; 3243 PIRP wdmIrp = WdfRequestWdmGetIrp(Request); 3244 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(wdmIrp); 3245 PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); 3246 3247 // Get the request parameters 3248 WDF_REQUEST_PARAMETERS_INIT(&requestParameters); 3249 WdfRequestGetParameters(Request, &requestParameters); 3250 3251 if (requestParameters.Type == WdfRequestTypeRead) 3252 { 3253 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, 3254 "Receiving READ, Length %Ix\n", (ULONG) Length)); 3255 } 3256 else 3257 { 3258 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, 3259 "Receiving WRITE, Length %Ix\n", (ULONG) Length)); 3260 } 3261 3262 // Check if a verify is required before a READ/WRITE 3263 if (TEST_FLAG(deviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME) && 3264 (requestParameters.MinorFunction != CDROM_VOLUME_VERIFY_CHECKED) && 3265 !TEST_FLAG(currentIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)) 3266 { 3267 // DO_VERIFY_VOLUME is set for the device object, 3268 // but this request is not itself a verify request. 3269 // So fail this request. 3270 RequestCompletion(deviceExtension, Request, STATUS_VERIFY_REQUIRED, 0); 3271 } 3272 else 3273 { 3274 // Since we've bypassed the verify-required tests we don't need to repeat 3275 // them with this IRP - in particular we don't want to worry about 3276 // hitting them at the partition 0 level if the request has come through 3277 // a non-zero partition. 3278 currentIrpStack->MinorFunction = CDROM_VOLUME_VERIFY_CHECKED; 3279 3280 // Fail READ/WRITE requests when music is playing 3281 if (deviceExtension->DeviceAdditionalData.PlayActive) 3282 { 3283 RequestCompletion(deviceExtension, Request, STATUS_DEVICE_BUSY, 0); 3284 3285 return; 3286 } 3287 3288 // Fail READ/WRITE requests from non-owners if the drive is locked 3289 if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request))) 3290 { 3291 RequestCompletion(deviceExtension, Request, STATUS_ACCESS_DENIED, 0); 3292 3293 return; 3294 } 3295 3296 // Succeed READ/WRITE requests of length 0 3297 if (Length == 0) 3298 { 3299 // Several parts of the code turn 0 into 0xffffffff, 3300 // so don't process a zero-length request any further. 3301 RequestCompletion(deviceExtension, Request, STATUS_SUCCESS, Length); 3302 3303 return; 3304 } 3305 3306 // If there is an unexpected write request, we want to rediscover MMC capabilities 3307 if (!deviceExtension->DeviceAdditionalData.Mmc.WriteAllowed && 3308 (requestParameters.Type == WdfRequestTypeWrite)) 3309 { 3310 // Schedule MMC capabilities update now, but perform it later in a work item 3311 deviceExtension->DeviceAdditionalData.Mmc.UpdateState = CdromMmcUpdateRequired; 3312 } 3313 3314 // If MMC capabilities update is required, we create a separate work item to avoid blocking 3315 // the current thread; otherwise, we initiate an async read/write in the current thread. 3316 if (DeviceIsMmcUpdateRequired(deviceExtension->Device)) 3317 { 3318 deviceExtension->ReadWriteWorkItemContext.OriginalRequest = Request; 3319 WdfWorkItemEnqueue(deviceExtension->ReadWriteWorkItem); 3320 3321 status = STATUS_SUCCESS; 3322 } 3323 else 3324 { 3325 status = RequestValidateReadWrite(deviceExtension, Request, requestParameters); 3326 3327 if (NT_SUCCESS(status)) 3328 { 3329 status = RequestHandleReadWrite(deviceExtension, Request, requestParameters); 3330 } 3331 } 3332 3333 if (!NT_SUCCESS(status)) 3334 { 3335 RequestCompletion(deviceExtension, Request, status, 0); 3336 } 3337 } 3338 3339 return; 3340 } 3341 3342 3343 VOID 3344 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 3345 ReadWriteWorkItemRoutine( 3346 _In_ WDFWORKITEM WorkItem 3347 ) 3348 /*++ 3349 3350 Routine Description: 3351 3352 Work item routine for validating and initiating read and write requests. 3353 The reason why we do that from a work item is because we may need to update MMC 3354 capabilities before validating a read/write request and that is a sync operation. 3355 3356 Arguments: 3357 3358 WorkItem - WDF work item 3359 3360 Return Value: 3361 3362 none 3363 3364 --*/ 3365 { 3366 PCDROM_DEVICE_EXTENSION deviceExtension = NULL; 3367 WDFREQUEST readWriteRequest = NULL; 3368 WDF_REQUEST_PARAMETERS readWriteRequestParameters; 3369 NTSTATUS status = STATUS_SUCCESS; 3370 3371 PAGED_CODE (); 3372 3373 deviceExtension = WdfObjectGetTypedContext(WdfWorkItemGetParentObject(WorkItem), CDROM_DEVICE_EXTENSION); 3374 readWriteRequest = deviceExtension->ReadWriteWorkItemContext.OriginalRequest; 3375 deviceExtension->ReadWriteWorkItemContext.OriginalRequest = NULL; 3376 3377 WDF_REQUEST_PARAMETERS_INIT(&readWriteRequestParameters); 3378 WdfRequestGetParameters(readWriteRequest, &readWriteRequestParameters); 3379 3380 if (DeviceIsMmcUpdateRequired(deviceExtension->Device)) 3381 { 3382 // Issue command to update the drive capabilities. 3383 // The failure of MMC update is not considered critical, so we'll 3384 // continue to process the request even if MMC update fails. 3385 (VOID) DeviceUpdateMmcCapabilities(deviceExtension->Device); 3386 } 3387 3388 // Now verify and process the request 3389 if (NT_SUCCESS(status)) 3390 { 3391 status = RequestValidateReadWrite(deviceExtension, readWriteRequest, readWriteRequestParameters); 3392 } 3393 if (NT_SUCCESS(status)) 3394 { 3395 status = RequestHandleReadWrite(deviceExtension, readWriteRequest, readWriteRequestParameters); 3396 } 3397 3398 // Complete the request immediately on failure 3399 if (!NT_SUCCESS(status)) 3400 { 3401 RequestCompletion(deviceExtension, readWriteRequest, status, 0); 3402 } 3403 } 3404 3405 3406 VOID 3407 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 3408 SequentialQueueEvtIoDeviceControl( 3409 _In_ WDFQUEUE Queue, 3410 _In_ WDFREQUEST Request, 3411 _In_ size_t OutputBufferLength, 3412 _In_ size_t InputBufferLength, 3413 _In_ ULONG IoControlCode 3414 ) 3415 /*++ 3416 Routine Description: 3417 3418 validate and process IOCTL request. 3419 3420 Arguments: 3421 3422 Queue - sequential queue 3423 3424 Request - handle to the incoming WDF Request object 3425 3426 Return Value: 3427 3428 None 3429 3430 --*/ 3431 { 3432 NTSTATUS status = STATUS_SUCCESS; 3433 WDFDEVICE device = WdfIoQueueGetDevice(Queue); 3434 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device); 3435 PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); 3436 PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); 3437 WDF_REQUEST_PARAMETERS requestParameters; 3438 3439 UNREFERENCED_PARAMETER(OutputBufferLength); 3440 UNREFERENCED_PARAMETER(InputBufferLength); 3441 UNREFERENCED_PARAMETER(IoControlCode); 3442 3443 // get the request parameters 3444 WDF_REQUEST_PARAMETERS_INIT(&requestParameters); 3445 WdfRequestGetParameters(Request, &requestParameters); 3446 3447 // If the device is in exclusive mode, check whether the request is from 3448 // the handle that locked the device 3449 if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request))) 3450 { 3451 BOOLEAN isBlocked = FALSE; 3452 3453 status = RequestIsIoctlBlockedByExclusiveAccess(Request, &isBlocked); 3454 if (NT_SUCCESS(status) && isBlocked) 3455 { 3456 if (requestContext->SyncRequired) 3457 { 3458 // set the following event, so RequestSynchronizeProcessWithSerialQueue() can contintue run to process the real request. 3459 // this function will wait for the request process finishes. 3460 KeSetEvent(requestContext->SyncEvent, IO_CD_ROM_INCREMENT, FALSE); 3461 } 3462 else 3463 { 3464 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 3465 "DeviceEvtIoInCallerContext: Access Denied! Device in exclusive mode.Failing Ioctl %lx\n", 3466 requestParameters.Parameters.DeviceIoControl.IoControlCode)); 3467 RequestCompletion(deviceExtension, Request, STATUS_ACCESS_DENIED, 0); 3468 } 3469 3470 return; 3471 } 3472 } 3473 3474 if (!cdData->Mmc.WriteAllowed && 3475 ((requestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_IS_WRITABLE) || 3476 (requestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_VERIFY))) 3477 { 3478 cdData->Mmc.UpdateState = CdromMmcUpdateRequired; 3479 } 3480 3481 // check if this is a synchronized ioctl 3482 if (requestContext->SyncRequired) 3483 { 3484 // set the following event, so RequestSynchronizeProcessWithSerialQueue() can contintue run to process the real request. 3485 // this function will wait for the request process finishes. 3486 KeSetEvent(requestContext->SyncEvent, IO_CD_ROM_INCREMENT, FALSE); 3487 } 3488 else 3489 { 3490 deviceExtension->IoctlWorkItemContext.OriginalRequest = Request; 3491 3492 // all other IOCTL processing is currently processed via a 3493 // work item running at PASSIVE_LEVEL. 3494 WdfWorkItemEnqueue(deviceExtension->IoctlWorkItem); 3495 } 3496 3497 return; 3498 } 3499 3500 3501 VOID 3502 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 3503 IoctlWorkItemRoutine( 3504 _In_ WDFWORKITEM WorkItem 3505 ) 3506 /*++ 3507 3508 Routine Description: 3509 3510 Work item routine for processing ioctl requests. 3511 This is needed because event callbacks are called at DISPATCH_LEVEL and ioctl 3512 requests are currently processed synchronously and not asynchronously. 3513 3514 Arguments: 3515 3516 WorkItem - WDF work item 3517 3518 Return Value: 3519 3520 none 3521 3522 --*/ 3523 { 3524 PCDROM_DEVICE_EXTENSION deviceExtension = NULL; 3525 3526 PAGED_CODE (); 3527 3528 deviceExtension = WdfObjectGetTypedContext(WdfWorkItemGetParentObject(WorkItem), CDROM_DEVICE_EXTENSION); 3529 3530 if (DeviceIsMmcUpdateRequired(deviceExtension->Device)) 3531 { 3532 // Issue command to update the drive capabilities. 3533 // The failure of MMC update is not considered critical, 3534 // so that we'll continue to process I/O even MMC update fails. 3535 DeviceUpdateMmcCapabilities(deviceExtension->Device); 3536 } 3537 3538 RequestProcessSerializedIoctl(deviceExtension, deviceExtension->IoctlWorkItemContext.OriginalRequest); 3539 } 3540 3541 3542 _IRQL_requires_max_(PASSIVE_LEVEL) 3543 NTSTATUS 3544 RequestProcessSerializedIoctl( 3545 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 3546 _In_ WDFREQUEST Request 3547 ) 3548 /*++ 3549 Routine Description: 3550 3551 a dispatch routine for all functions to process IOCTLs. 3552 3553 Arguments: 3554 3555 DeviceExtension - device context 3556 3557 Request - handle to the incoming WDF Request object 3558 3559 Return Value: 3560 3561 NTSTATUS 3562 3563 --*/ 3564 { 3565 NTSTATUS status = STATUS_SUCCESS; 3566 size_t information = 0; 3567 WDF_REQUEST_PARAMETERS requestParameters; 3568 BOOLEAN completeRequest = TRUE; 3569 3570 PAGED_CODE (); 3571 3572 // Get the Request parameters 3573 WDF_REQUEST_PARAMETERS_INIT(&requestParameters); 3574 WdfRequestGetParameters(Request, &requestParameters); 3575 3576 NormalizeIoctl(&requestParameters); 3577 3578 // process IOCTLs 3579 switch (requestParameters.Parameters.DeviceIoControl.IoControlCode) 3580 { 3581 case IOCTL_CDROM_READ_TOC: 3582 case IOCTL_CDROM_GET_LAST_SESSION: 3583 status = RequestHandleReadTOC(DeviceExtension, Request, requestParameters, &information); 3584 break; 3585 3586 case IOCTL_CDROM_READ_TOC_EX: 3587 status = RequestHandleReadTocEx(DeviceExtension, Request, requestParameters, &information); 3588 break; 3589 3590 case IOCTL_CDROM_GET_CONFIGURATION: 3591 status = RequestHandleGetConfiguration(DeviceExtension, Request, requestParameters, &information); 3592 break; 3593 3594 case IOCTL_CDROM_RAW_READ: 3595 status = DeviceHandleRawRead(DeviceExtension, Request, requestParameters, &information); 3596 break; 3597 3598 case IOCTL_DISK_GET_LENGTH_INFO: 3599 case IOCTL_DISK_GET_DRIVE_GEOMETRY: 3600 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: 3601 case IOCTL_CDROM_GET_DRIVE_GEOMETRY: 3602 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX: 3603 case IOCTL_STORAGE_READ_CAPACITY: 3604 status = RequestHandleGetDriveGeometry(DeviceExtension, Request, requestParameters, &information); 3605 break; 3606 3607 case IOCTL_DISK_VERIFY: 3608 status = RequestHandleDiskVerify(DeviceExtension, Request, requestParameters, &information); 3609 break; 3610 3611 case IOCTL_STORAGE_CHECK_VERIFY: 3612 // IOCTL_STORAGE_CHECK_VERIFY2 was processed including send a Test Unit Read 3613 // with srb flag SRB_CLASS_FLAGS_LOW_PRIORITY to port driver asynchronizelly. 3614 // The original request was completed after TUR finishes. 3615 // As CDROM.SYS serializes IOs need accessing device, it's not a big difference from above behavior to 3616 // just process it in serialized manner. So I put it here and treat it as same as IOCTL_STORAGE_CHECK_VERIFY. 3617 case IOCTL_STORAGE_CHECK_VERIFY2: 3618 status = RequestHandleCheckVerify(DeviceExtension, Request, requestParameters, &information); 3619 break; 3620 3621 case IOCTL_DISK_GET_DRIVE_LAYOUT: 3622 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: 3623 case IOCTL_DISK_GET_PARTITION_INFO: 3624 case IOCTL_DISK_GET_PARTITION_INFO_EX: 3625 status = RequestHandleFakePartitionInfo(DeviceExtension, Request, requestParameters, &information); 3626 break; 3627 3628 case IOCTL_DISK_IS_WRITABLE: 3629 // 3630 // Even though this media is writable, the requester of this IOCTL really 3631 // wants to know if thw media behaves like any other disk or not. This is 3632 // so if FeatureDefectManagement and FeatureRandomWritable are current on 3633 // the drive-represented by the FeatureDefectManagement validation schema 3634 // 3635 if (DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed && 3636 (DeviceExtension->DeviceAdditionalData.Mmc.ValidationSchema == FeatureDefectManagement)) 3637 { 3638 status = STATUS_SUCCESS; 3639 } 3640 else 3641 { 3642 status = STATUS_MEDIA_WRITE_PROTECTED; 3643 } 3644 information = 0; 3645 break; 3646 3647 case IOCTL_CDROM_PLAY_AUDIO_MSF: 3648 status = DeviceHandlePlayAudioMsf(DeviceExtension, Request, requestParameters, &information); 3649 break; 3650 3651 case IOCTL_CDROM_READ_Q_CHANNEL: 3652 status = DeviceHandleReadQChannel(DeviceExtension, Request, requestParameters, &information); 3653 break; 3654 3655 case IOCTL_CDROM_PAUSE_AUDIO: 3656 status = DeviceHandlePauseAudio(DeviceExtension, Request, &information); 3657 break; 3658 3659 case IOCTL_CDROM_RESUME_AUDIO: 3660 status = DeviceHandleResumeAudio(DeviceExtension, Request, &information); 3661 break; 3662 3663 case IOCTL_CDROM_SEEK_AUDIO_MSF: 3664 status = DeviceHandleSeekAudioMsf(DeviceExtension, Request, requestParameters, &information); 3665 break; 3666 3667 case IOCTL_CDROM_STOP_AUDIO: 3668 status = DeviceHandleStopAudio(DeviceExtension, Request, &information); 3669 break; 3670 3671 case IOCTL_CDROM_GET_VOLUME: 3672 case IOCTL_CDROM_SET_VOLUME: 3673 status = DeviceHandleGetSetVolume(DeviceExtension, Request, requestParameters, &information); 3674 break; 3675 3676 case IOCTL_DVD_GET_REGION: 3677 status = RequestHandleGetDvdRegion(DeviceExtension, Request, &information); 3678 break; 3679 3680 case IOCTL_DVD_READ_STRUCTURE: 3681 status = DeviceHandleReadDvdStructure(DeviceExtension, Request, requestParameters, &information); 3682 break; 3683 3684 case IOCTL_DVD_END_SESSION: 3685 status = DeviceHandleDvdEndSession(DeviceExtension, Request, requestParameters, &information); 3686 break; 3687 3688 case IOCTL_DVD_START_SESSION: 3689 case IOCTL_DVD_READ_KEY: 3690 status = DeviceHandleDvdStartSessionReadKey(DeviceExtension, Request, requestParameters, &information); 3691 break; 3692 3693 case IOCTL_DVD_SEND_KEY: 3694 case IOCTL_DVD_SEND_KEY2: 3695 status = DeviceHandleDvdSendKey(DeviceExtension, Request, requestParameters, &information); 3696 break; 3697 3698 case IOCTL_STORAGE_SET_READ_AHEAD: 3699 status = DeviceHandleSetReadAhead(DeviceExtension, Request, requestParameters, &information); 3700 break; 3701 3702 case IOCTL_CDROM_SET_SPEED: 3703 status = DeviceHandleSetSpeed(DeviceExtension, Request, requestParameters, &information); 3704 break; 3705 3706 case IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE: 3707 case IOCTL_AACS_READ_MEDIA_KEY_BLOCK: 3708 status = DeviceHandleAacsReadMediaKeyBlock(DeviceExtension, Request, requestParameters, &information); 3709 break; 3710 3711 case IOCTL_AACS_START_SESSION: 3712 status = DeviceHandleAacsStartSession(DeviceExtension, Request, requestParameters, &information); 3713 break; 3714 3715 case IOCTL_AACS_END_SESSION: 3716 status = DeviceHandleAacsEndSession(DeviceExtension, Request, requestParameters, &information); 3717 break; 3718 3719 case IOCTL_AACS_SEND_CERTIFICATE: 3720 status = DeviceHandleAacsSendCertificate(DeviceExtension, Request, requestParameters, &information); 3721 break; 3722 3723 case IOCTL_AACS_GET_CERTIFICATE: 3724 status = DeviceHandleAacsGetCertificate(DeviceExtension, Request, requestParameters, &information); 3725 break; 3726 3727 case IOCTL_AACS_GET_CHALLENGE_KEY: 3728 status = DeviceHandleAacsGetChallengeKey(DeviceExtension, Request, requestParameters, &information); 3729 break; 3730 3731 case IOCTL_AACS_SEND_CHALLENGE_KEY: 3732 status = DeviceHandleSendChallengeKey(DeviceExtension, Request, requestParameters, &information); 3733 break; 3734 3735 case IOCTL_AACS_READ_VOLUME_ID: 3736 status = DeviceHandleReadVolumeId(DeviceExtension, Request, requestParameters, &information); 3737 break; 3738 3739 case IOCTL_AACS_READ_SERIAL_NUMBER: 3740 status = DeviceHandleAacsReadSerialNumber(DeviceExtension, Request, requestParameters, &information); 3741 break; 3742 3743 case IOCTL_AACS_READ_MEDIA_ID: 3744 status = DeviceHandleAacsReadMediaId(DeviceExtension, Request, requestParameters, &information); 3745 break; 3746 3747 case IOCTL_AACS_READ_BINDING_NONCE: 3748 status = DeviceHandleAacsReadBindingNonce(DeviceExtension, Request, requestParameters, &information); 3749 break; 3750 3751 case IOCTL_AACS_GENERATE_BINDING_NONCE: 3752 status = DeviceHandleAacsGenerateBindingNonce(DeviceExtension, Request, requestParameters, &information); 3753 break; 3754 3755 case IOCTL_CDROM_ENABLE_STREAMING: 3756 status = RequestHandleEnableStreaming(DeviceExtension, Request, &information); 3757 break; 3758 3759 case IOCTL_CDROM_SEND_OPC_INFORMATION: 3760 status = RequestHandleSendOpcInformation(DeviceExtension, Request, &information); 3761 break; 3762 3763 case IOCTL_CDROM_GET_PERFORMANCE: 3764 status = RequestHandleGetPerformance(DeviceExtension, Request, requestParameters, &information); 3765 break; 3766 3767 // This IOCTL is a fake one, used for MCN process sync-ed with serial queue. 3768 case IOCTL_MCN_SYNC_FAKE_IOCTL: 3769 status = RequestHandleMcnSyncFakeIoctl(DeviceExtension, &information); 3770 break; 3771 3772 case IOCTL_STORAGE_MEDIA_REMOVAL: 3773 case IOCTL_STORAGE_EJECTION_CONTROL: 3774 { 3775 status = RequestHandleEjectionControl(DeviceExtension, Request, requestParameters, &information); 3776 3777 break; 3778 } 3779 3780 case IOCTL_STORAGE_EJECT_MEDIA: 3781 case IOCTL_STORAGE_LOAD_MEDIA: 3782 case IOCTL_STORAGE_LOAD_MEDIA2: 3783 { 3784 status = RequestHandleLoadEjectMedia(DeviceExtension, Request, requestParameters, &information); 3785 3786 break; 3787 } 3788 3789 case IOCTL_STORAGE_MCN_CONTROL: 3790 { 3791 status = RequestHandleMcnControl(DeviceExtension, Request, &information); 3792 3793 break; 3794 } 3795 3796 case IOCTL_STORAGE_RESERVE: 3797 case IOCTL_STORAGE_RELEASE: 3798 { 3799 status = RequestHandleReserveRelease(DeviceExtension, Request, requestParameters, &information); 3800 3801 break; 3802 } 3803 3804 case IOCTL_STORAGE_PERSISTENT_RESERVE_IN: 3805 case IOCTL_STORAGE_PERSISTENT_RESERVE_OUT: 3806 { 3807 status = RequestHandlePersistentReserve(DeviceExtension, Request, requestParameters, &information); 3808 3809 break; 3810 } 3811 3812 #if (NTDDI_VERSION >= NTDDI_WIN8) 3813 case IOCTL_DISK_ARE_VOLUMES_READY: 3814 { 3815 status = RequestHandleAreVolumesReady(DeviceExtension, Request, requestParameters, &information); 3816 3817 completeRequest = FALSE; 3818 3819 break; 3820 } 3821 3822 case IOCTL_VOLUME_ONLINE: 3823 case IOCTL_VOLUME_POST_ONLINE: 3824 { 3825 status = RequestHandleVolumeOnline(DeviceExtension, Request, requestParameters, &information); 3826 3827 break; 3828 } 3829 #endif 3830 3831 default: 3832 { 3833 status = STATUS_ACCESS_DENIED; 3834 break; 3835 } 3836 } // end of switch(ioctl) 3837 3838 if (completeRequest) 3839 { 3840 RequestCompletion(DeviceExtension, Request, status, information); 3841 } 3842 3843 return status; 3844 } 3845 3846 VOID 3847 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 3848 SequentialQueueEvtCanceledOnQueue( 3849 _In_ WDFQUEUE Queue, 3850 _In_ WDFREQUEST Request 3851 ) 3852 /*++ 3853 Routine Description: 3854 3855 Perform cancellation when request is still in queue. 3856 3857 If request is sych-ed in another thread, signal the event to let that thread be able to complete the request. 3858 Otherwise, complete the request. 3859 3860 Arguments: 3861 3862 Queue - serial queue 3863 Request - handle to the incoming WDF Request object 3864 3865 Return Value: 3866 3867 None 3868 3869 --*/ 3870 { 3871 PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); 3872 3873 if (requestContext->SyncRequired) 3874 { 3875 KeSetEvent(requestContext->SyncEvent, IO_CD_ROM_INCREMENT, FALSE); 3876 } 3877 else 3878 { 3879 PCDROM_DEVICE_EXTENSION deviceExtension = NULL; 3880 WDFDEVICE device = WdfIoQueueGetDevice(Queue); 3881 3882 deviceExtension = DeviceGetExtension(device); 3883 3884 RequestCompletion(deviceExtension, Request, STATUS_CANCELLED, 0); 3885 3886 } 3887 3888 return; 3889 } 3890 3891 3892 NTSTATUS 3893 RequestSynchronizeProcessWithSerialQueue( 3894 _In_ WDFDEVICE Device, 3895 _In_ WDFREQUEST Request 3896 ) 3897 /*++ 3898 Routine Description: 3899 3900 This is the mechanism to sync a request process in original thread with serialize queue. 3901 initialize a EVENT and put the request inot serialize queue; 3902 waiting for serialize queue processes to this request and signal the EVENT; 3903 call the request handler to process this request. 3904 3905 Arguments: 3906 3907 DeviceExtension - device context 3908 3909 Request - handle to the incoming WDF Request object 3910 3911 Return Value: 3912 3913 NTSTATUS 3914 3915 --*/ 3916 { 3917 NTSTATUS status = STATUS_SUCCESS; 3918 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); 3919 PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); 3920 PKEVENT bufferToFree = requestContext->SyncEvent; 3921 3922 if (KeGetCurrentIrql() >= DISPATCH_LEVEL) { 3923 // cannot block at or above DISPATCH_LEVEL 3924 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 3925 "RequestSynchronousProcessWithSerialQueue called at DISPATCH_LEVEL or above")); 3926 NT_ASSERT(FALSE); 3927 RequestCompletion(deviceExtension, Request, STATUS_INVALID_LEVEL, 0); 3928 return STATUS_INVALID_LEVEL; 3929 } 3930 3931 // init the synchronization event 3932 KeInitializeEvent(requestContext->SyncEvent, NotificationEvent, FALSE); 3933 3934 // do we still need to do something like this? 3935 // SET_FLAG(nextStack->Flags, SL_OVERRIDE_VERIFY_VOLUME); 3936 3937 // NOTE: this mechanism relies on that KMDF will not complete request by itself. 3938 // Doing that will cause the syncEvent not fired thus this thread will stuck. 3939 // This should not really happen: our EvtCanceledOnQueue callbacks should be 3940 // called even if queues are purged for some reason. The only case when these 3941 // callbacks are not called is when a request is owned by the driver (i.e. has 3942 // already been passed to one of the registered handlers). In this case, it is 3943 // our responsibility to cancel such requests properly. 3944 status = WdfDeviceEnqueueRequest(Device, Request); 3945 3946 if (!NT_SUCCESS(status)) 3947 { 3948 // Failed to forward request! Pretend the sync event already occured, otherwise we'll hit 3949 // an assert in RequestEvtCleanup. 3950 KeSetEvent(requestContext->SyncEvent, IO_CD_ROM_INCREMENT, FALSE); 3951 RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request)); 3952 } 3953 else 3954 { 3955 NTSTATUS waitStatus = STATUS_UNSUCCESSFUL; 3956 PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); 3957 BOOLEAN fCallSyncCallback = FALSE; 3958 PIRP irp = WdfRequestWdmGetIrp(Request); 3959 3960 // ok, now wait on the event 3961 while (waitStatus != STATUS_SUCCESS) 3962 { 3963 waitStatus = KeWaitForSingleObject(requestContext->SyncEvent, Executive, KernelMode, TRUE, NULL); 3964 if (waitStatus == STATUS_SUCCESS) // must check equality -- STATUS_ALERTED is success code 3965 { 3966 // do nothing 3967 } 3968 else if (waitStatus != STATUS_ALERTED) 3969 { 3970 // do nothing 3971 TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_IOCTL, 3972 "Request %p on device object %p had a non-alert, non-success result from wait (%!HRESULT!)\n", 3973 Request, Device, waitStatus)); 3974 NT_ASSERT(FALSE); 3975 } 3976 else if (PsIsThreadTerminating(PsGetCurrentThread())) 3977 { 3978 // the thread was alerted and is terminating, so cancel the irp 3979 // this will cause EvtIoCanceledOnQueue to be called, which will signal the event, 3980 // so we will get out of the while loop and eventually complete the request. 3981 if (IoCancelIrp(irp)) 3982 { 3983 // cancellation routine was called 3984 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 3985 "Sychronize Ioctl: request %p cancelled from device %p\n", 3986 Request, Device)); 3987 } 3988 else 3989 { 3990 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 3991 "Sychronize Ioctl: request %p could not be cancelled from device %p\n", 3992 Request, Device)); 3993 } 3994 } 3995 else 3996 { 3997 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, 3998 "SPURIOUS ALERT waiting for Request %p on device %p (%!STATUS!)\n", 3999 Request, Device, status)); 4000 } 4001 } // end of wait loop on the event 4002 4003 // because we've waited an unknown amount of time, should check 4004 // the cancelled flag to immediately fail the irp as appropriate 4005 if (WdfRequestIsCanceled(Request)) 4006 { 4007 // the request was cancelled, thus we should always stop 4008 // processing here if possible. 4009 status = STATUS_CANCELLED; 4010 RequestCompletion(deviceExtension, Request, status, 0); 4011 } 4012 else if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request))) 4013 { 4014 WDF_REQUEST_PARAMETERS requestParameters; 4015 BOOLEAN isBlocked = FALSE; 4016 4017 // get the request parameters 4018 WDF_REQUEST_PARAMETERS_INIT(&requestParameters); 4019 WdfRequestGetParameters(Request, &requestParameters); 4020 4021 status = RequestIsIoctlBlockedByExclusiveAccess(Request, &isBlocked); 4022 if (isBlocked) 4023 { 4024 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, 4025 "Access Denied! Device in exclusive mode.Failing Ioctl %lx\n", 4026 requestParameters.Parameters.DeviceIoControl.IoControlCode)); 4027 RequestCompletion(deviceExtension, Request, STATUS_ACCESS_DENIED, 0); 4028 } 4029 else 4030 { 4031 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, 4032 "Ioctl %lx not blocked by cdrom being in exclusive mode\n", 4033 requestParameters.Parameters.DeviceIoControl.IoControlCode)); 4034 fCallSyncCallback = TRUE; 4035 } 4036 } 4037 else 4038 { 4039 fCallSyncCallback = TRUE; 4040 } 4041 4042 if (fCallSyncCallback) 4043 { 4044 // Synchronization completed successfully. Call the requested routine 4045 status = requestContext->SyncCallback(Device, Request); 4046 } 4047 } 4048 4049 // The next SequentialQueue evt routine will not be triggered until the current request is completed. 4050 4051 // clean up the request context setting. 4052 FREE_POOL(bufferToFree); 4053 4054 return status; 4055 } 4056 4057 NTSTATUS 4058 RequestIsIoctlBlockedByExclusiveAccess( 4059 _In_ WDFREQUEST Request, 4060 _Out_ PBOOLEAN IsBlocked 4061 ) 4062 /*++ 4063 Routine Description: 4064 4065 Check if the IOCTL request should be blocked or not according to 4066 the exclusive lock stat. 4067 4068 Arguments: 4069 4070 Request - handle to the incoming WDF Request object 4071 4072 Return Value: 4073 4074 NTSTATUS 4075 4076 IsBlocked - TRUE (be blocked); FALSE (not blocked) 4077 4078 --*/ 4079 { 4080 NTSTATUS status = STATUS_SUCCESS; 4081 ULONG ioctlCode = 0; 4082 ULONG baseCode = 0; 4083 WDF_REQUEST_PARAMETERS requestParameters; 4084 4085 // Get the Request parameters 4086 WDF_REQUEST_PARAMETERS_INIT(&requestParameters); 4087 WdfRequestGetParameters(Request, &requestParameters); 4088 4089 // check and initialize parameter 4090 if (IsBlocked == NULL) 4091 { 4092 //This is an internal function and this parameter must be supplied. 4093 NT_ASSERT(FALSE); 4094 4095 return STATUS_INVALID_PARAMETER; 4096 } 4097 else 4098 { 4099 *IsBlocked = FALSE; 4100 } 4101 4102 // check if this is an IOCTL 4103 if ((requestParameters.Type == WdfRequestTypeDeviceControl) || 4104 (requestParameters.Type == WdfRequestTypeDeviceControlInternal)) 4105 { 4106 // 4107 // Allow minimum set of commands that are required for the disk manager 4108 // to show the CD device, while in exclusive mode. 4109 // Note: These commands should not generate any requests to the device, 4110 // and thus must be handled directly in StartIO during exclusive 4111 // access (except for the exclusive owner, of course). 4112 // 4113 ioctlCode = requestParameters.Parameters.DeviceIoControl.IoControlCode; 4114 baseCode = DEVICE_TYPE_FROM_CTL_CODE(ioctlCode); 4115 4116 if (ioctlCode == IOCTL_SCSI_GET_ADDRESS || 4117 ioctlCode == IOCTL_STORAGE_GET_HOTPLUG_INFO || 4118 ioctlCode == IOCTL_STORAGE_GET_DEVICE_NUMBER || 4119 ioctlCode == IOCTL_STORAGE_GET_MEDIA_TYPES_EX || 4120 ioctlCode == IOCTL_CDROM_EXCLUSIVE_ACCESS || 4121 ioctlCode == IOCTL_CDROM_GET_INQUIRY_DATA 4122 ) 4123 { 4124 *IsBlocked = FALSE; 4125 } 4126 4127 // 4128 // Handle IOCTL_STORAGE_QUERY_PROPERTY special because: 4129 // (1) PropertyExistsQuery should not generate device i/o 4130 // (2) Queries for StorageDeviceProperty and StorageAdapterDescriptor 4131 // will return cache'd data 4132 else if (ioctlCode == IOCTL_STORAGE_QUERY_PROPERTY) 4133 { 4134 PSTORAGE_PROPERTY_QUERY query = NULL; 4135 status = WdfRequestRetrieveInputBuffer(Request, 4136 requestParameters.Parameters.DeviceIoControl.InputBufferLength, 4137 (PVOID*)&query, 4138 NULL); 4139 4140 if (NT_SUCCESS(status)) 4141 { 4142 if (query != NULL) 4143 { 4144 if (query->QueryType == PropertyExistsQuery) 4145 { 4146 *IsBlocked = FALSE; 4147 } 4148 else if ((query->QueryType == PropertyStandardQuery) && 4149 ((query->PropertyId == StorageDeviceProperty) || 4150 (query->PropertyId == StorageAdapterProperty))) 4151 { 4152 *IsBlocked = FALSE; 4153 } 4154 } 4155 } 4156 } 4157 4158 // Return TRUE for unknown IOCTLs with STORAGE bases 4159 else if (baseCode == IOCTL_SCSI_BASE || 4160 baseCode == IOCTL_DISK_BASE || 4161 baseCode == IOCTL_CDROM_BASE || 4162 baseCode == IOCTL_STORAGE_BASE || 4163 baseCode == IOCTL_DVD_BASE ) 4164 { 4165 *IsBlocked = TRUE; 4166 } 4167 } 4168 else 4169 { 4170 // this should only be called with an IOCTL 4171 NT_ASSERT(FALSE); 4172 4173 status = STATUS_INVALID_PARAMETER; 4174 } 4175 4176 return status; 4177 } 4178 4179 BOOLEAN 4180 DeviceIsMmcUpdateRequired( 4181 _In_ WDFDEVICE Device 4182 ) 4183 /*++ 4184 Routine Description: 4185 4186 Check if the device needs to update its MMC information. 4187 4188 Arguments: 4189 4190 Device - device to be checked. 4191 4192 Return Value: 4193 4194 TRUE (require update); FALSE (not require update) 4195 4196 --*/ 4197 { 4198 PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); 4199 PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); 4200 4201 if ((cdData->Mmc.IsMmc) && 4202 (cdData->Mmc.UpdateState == CdromMmcUpdateRequired)) 4203 { 4204 return TRUE; 4205 } 4206 else 4207 { 4208 // no update required: just proceed 4209 return FALSE; 4210 } 4211 } 4212 4213 VOID 4214 NTAPI /* ReactOS Change: GCC Does not support STDCALL by default */ 4215 RequestEvtCleanup( 4216 _In_ WDFOBJECT Request 4217 ) 4218 /*++ 4219 Routine Description: 4220 4221 Request cleanup callback. 4222 4223 Arguments: 4224 4225 Request - request to clean up. 4226 4227 Return Value: 4228 4229 None 4230 4231 --*/ 4232 { 4233 WDFREQUEST request = (WDFREQUEST)Request; 4234 PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(request); 4235 4236 if (requestContext->SyncRequired) 4237 { 4238 // the event should have been signaled, just check that 4239 NT_ASSERT(KeReadStateEvent(requestContext->SyncEvent) != 0); 4240 } 4241 } 4242 4243