3 Copyright (C) Microsoft Corporation. All rights reserved.
11 The CDROM class driver tranlates IRPs to SRBs with embedded CDBs
12 and sends them to its devices through the port driver.
25 // this definition is used to link _StorDebugPrint() function.
26 #define DEBUG_MAIN_SOURCE 1
30 #include "ntstrsafe.h"
48 BootEnvironmentIsWinPE(
54 #pragma alloc_text(INIT, DriverEntry)
55 #pragma alloc_text(INIT, BootEnvironmentIsWinPE)
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)
74 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
76 _In_ PDRIVER_OBJECT DriverObject
,
77 _In_ PUNICODE_STRING RegistryPath
83 Installable driver initialization entry point.
84 This entry point is called directly by the I/O system.
88 DriverObject - pointer to the driver object
90 RegistryPath - pointer to a unicode string representing the path,
91 to driver-specific key in the registry.
95 STATUS_SUCCESS if successful,
96 STATUS_UNSUCCESSFUL otherwise.
101 WDF_DRIVER_CONFIG config
;
102 WDF_OBJECT_ATTRIBUTES attributes
;
103 WDFDRIVER driverObject
= NULL
;
107 // Initialize WPP Tracing
108 WPP_INIT_TRACING(DriverObject
, RegistryPath
);
110 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_INIT
,
111 "CDROM.SYS DriverObject %p loading\n",
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
;
119 WDF_DRIVER_CONFIG_INIT(&config
, DriverEvtDeviceAdd
);
121 status
= WdfDriverCreate(DriverObject
,
127 if (!NT_SUCCESS(status
))
129 TracePrint((TRACE_LEVEL_FATAL
, TRACE_FLAG_INIT
,
130 "WdfDriverCreate failed. %x\n",
133 // Cleanup tracing here because DriverUnload will not be called
134 // as we have failed to create WDFDRIVER object itself.
135 WPP_CLEANUP(DriverObject
);
140 PCDROM_DRIVER_EXTENSION driverExtension
= DriverGetExtension(driverObject
);
142 // Copy the registry path into the driver extension so we can use it later
143 driverExtension
->Version
= 0x01;
144 driverExtension
->DriverObject
= DriverObject
;
146 if (BootEnvironmentIsWinPE()) {
148 SET_FLAG(driverExtension
->Flags
, CDROM_FLAG_WINPE_MODE
);
158 BootEnvironmentIsWinPE(
165 This routine determines if the boot enviroment is WinPE
173 BOOLEAN - TRUE if the environment is WinPE; FALSE otherwise
178 WDFKEY registryKey
= NULL
;
180 DECLARE_CONST_UNICODE_STRING(registryKeyName
, WINPE_REG_KEY_NAME
);
184 status
= WdfRegistryOpenKey(NULL
,
187 WDF_NO_OBJECT_ATTRIBUTES
,
190 if (!NT_SUCCESS(status
))
195 WdfRegistryClose(registryKey
);
197 } // end BootEnvironmentIsWinPE()
201 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
203 _In_ WDFOBJECT Driver
208 Free all the resources allocated in DriverEntry.
212 Driver - handle to a WDF Driver object.
220 WDFDRIVER driver
= (WDFDRIVER
)Driver
;
224 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_INIT
,
225 "CDROM.SYS DriverObject %p cleanup. Will be unloaded soon\n",
229 WPP_CLEANUP( WdfDriverWdmGetDriverObject(driver
) );
237 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
239 _In_ WDFDRIVER Driver
,
240 _Inout_ PWDFDEVICE_INIT DeviceInit
246 EvtDeviceAdd is called by the framework in response to AddDevice
247 call from the PnP manager.
252 Driver - Handle to a framework driver object created in DriverEntry
254 DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.
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
;
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
;
284 driverExtension
= DriverGetExtension(Driver
);
286 // 0. Initialize the objects that we're going to use
287 RtlInitUnicodeString(&unicodeDeviceName
, NULL
);
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.
292 // Zero out the PnpPowerCallbacks structure.
293 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks
);
295 // Use this callback to init resources that are used by the device and only needs to be called once.
296 pnpPowerCallbacks
.EvtDeviceSelfManagedIoInit
= DeviceEvtSelfManagedIoInit
;
298 // Use this callback to prepare device for coming back from a lower power mode to D0.
299 pnpPowerCallbacks
.EvtDeviceD0Entry
= DeviceEvtD0Entry
;
301 // Use this callback to prepare device for entering into a lower power mode.
302 pnpPowerCallbacks
.EvtDeviceD0Exit
= DeviceEvtD0Exit
;
304 // Use this callback to free any resources used by device and will be called when the device is
306 pnpPowerCallbacks
.EvtDeviceSelfManagedIoCleanup
= DeviceEvtSelfManagedIoCleanup
;
308 pnpPowerCallbacks
.EvtDeviceSurpriseRemoval
= DeviceEvtSurpriseRemoval
;
310 // Register the PnP and power callbacks.
311 WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit
, &pnpPowerCallbacks
);
314 // 2. Register the EvtIoInCallerContext to deal with IOCTLs that need to stay in original context.
315 WdfDeviceInitSetIoInCallerContextCallback(DeviceInit
,
316 DeviceEvtIoInCallerContext
);
318 // 3. Register PreprocessCallback for IRP_MJ_POWER, IRP_MJ_FLUSH_BUFFERS and IRP_MJ_SHUTDOWN
320 UCHAR minorFunctions
[1];
322 minorFunctions
[0] = IRP_MN_SET_POWER
;
324 status
= WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit
,
325 RequestProcessSetPower
,
328 RTL_NUMBER_OF(minorFunctions
));
329 if (!NT_SUCCESS(status
))
331 TracePrint((TRACE_LEVEL_FATAL
, TRACE_FLAG_PNP
,
332 "DriverEvtDeviceAdd: Assign IrpPreprocessCallback for IRP_MJ_POWER failed, "
333 "status: 0x%X\n", status
));
338 status
= WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit
,
339 RequestProcessShutdownFlush
,
340 IRP_MJ_FLUSH_BUFFERS
,
343 if (!NT_SUCCESS(status
))
345 TracePrint((TRACE_LEVEL_FATAL
, TRACE_FLAG_PNP
,
346 "DriverEvtDeviceAdd: Assign IrpPreprocessCallback for IRP_MJ_FLUSH_BUFFERS failed, "
347 "status: 0x%X\n", status
));
352 status
= WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit
,
353 RequestProcessShutdownFlush
,
357 if (!NT_SUCCESS(status
))
359 TracePrint((TRACE_LEVEL_FATAL
, TRACE_FLAG_PNP
,
360 "DriverEvtDeviceAdd: Assign IrpPreprocessCallback for IRP_MJ_SHUTDOWN failed, "
361 "status: 0x%X\n", status
));
367 // 4. Set attributes to create Request Context area.
369 //Reuse this structure.
370 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes
,
371 CDROM_REQUEST_CONTEXT
);
372 attributes
.EvtCleanupCallback
= RequestEvtCleanup
;
374 WdfDeviceInitSetRequestAttributes(DeviceInit
,
378 // 5. Register FileObject related callbacks
380 // Add FILE_OBJECT_EXTENSION as the context to the file object.
381 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes
, FILE_OBJECT_CONTEXT
);
383 // Set Entry points for Create and Close..
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,
391 WDF_NO_EVENT_CALLBACK
); // No callback for Cleanup
393 fileObjectConfig
.FileObjectClass
= WdfFileObjectWdfCannotUseFsContexts
;
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
;
402 // Indicate that file object is optional.
403 fileObjectConfig
.FileObjectClass
|= WdfFileObjectCanBeOptional
;
405 WdfDeviceInitSetFileObjectConfig(DeviceInit
,
410 // 6. Initialize device-wide attributes
412 // Declare ourselves as NOT owning power policy.
413 // The power policy owner in storage stack is port driver.
414 WdfDeviceInitSetPowerPolicyOwnership(DeviceInit
, FALSE
);
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
);
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
);
427 WdfDeviceInitSetRemoveLockOptions(DeviceInit
, &removeLockOptions
);
429 // save the PDO for later reference
430 lowerPdo
= WdfFdoInitWdmGetPhysicalDevice(DeviceInit
);
432 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes
,
433 CDROM_DEVICE_EXTENSION
);
435 // We have a parallel queue, so WdfSynchronizationScopeNone is our only choice.
436 attributes
.SynchronizationScope
= WdfSynchronizationScopeNone
;
437 attributes
.ExecutionLevel
= WdfExecutionLevelDispatch
;
439 // Provide a cleanup callback which will release memory allocated with ExAllocatePool*
440 attributes
.EvtCleanupCallback
= DeviceEvtCleanup
;
443 // 7. Now, the device can be created.
445 wideDeviceName
= ExAllocatePoolWithTag(NonPagedPoolNx
,
449 if (wideDeviceName
== NULL
)
451 status
= STATUS_INSUFFICIENT_RESOURCES
;
455 // Find the lowest device number currently available.
457 status
= RtlStringCchPrintfW((NTSTRSAFE_PWSTR
)wideDeviceName
,
459 L
"\\Device\\CdRom%d",
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
));
469 RtlInitUnicodeString(&unicodeDeviceName
, wideDeviceName
);
471 status
= WdfDeviceInitAssignName(DeviceInit
, &unicodeDeviceName
);
472 if (!NT_SUCCESS(status
))
474 TracePrint((TRACE_LEVEL_FATAL
, TRACE_FLAG_PNP
,
475 "DriverEvtDeviceAdd: WdfDeviceInitAssignName() failed with error: 0x%X\n", status
));
480 status
= WdfDeviceCreate(&DeviceInit
, &attributes
, &device
);
484 } while (status
== STATUS_OBJECT_NAME_COLLISION
);
486 // When this loop exits the count is inflated by one - fix that.
489 if (!NT_SUCCESS(status
))
491 TracePrint((TRACE_LEVEL_FATAL
, TRACE_FLAG_PNP
,
492 "DriverEvtDeviceAdd: Can not create a new device, status: 0x%X\n",
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.
503 deviceExtension
= DeviceGetExtension(device
);
505 deviceExtension
->Version
= 0x01;
506 deviceExtension
->Size
= sizeof(CDROM_DEVICE_EXTENSION
);
508 deviceExtension
->DeviceObject
= WdfDeviceWdmGetDeviceObject(device
);
509 deviceExtension
->Device
= device
;
510 deviceExtension
->DriverExtension
= driverExtension
;
512 deviceExtension
->LowerPdo
= lowerPdo
;
514 deviceExtension
->DeviceType
= FILE_DEVICE_CD_ROM
; //Always a FILE_DEVICE_CD_ROM for all device it manages.
515 deviceExtension
->DeviceName
= unicodeDeviceName
;
517 deviceExtension
->DeviceNumber
= deviceNumber
;
520 WDF_OBJECT_ATTRIBUTES_INIT(&attributes
);
521 attributes
.ParentObject
= deviceExtension
->Device
;
523 status
= WdfIoTargetCreate(deviceExtension
->Device
,
525 &deviceExtension
->IoTarget
);
527 if (!NT_SUCCESS(status
))
529 TracePrint((TRACE_LEVEL_FATAL
, TRACE_FLAG_PNP
,
530 "DriverEvtDeviceAdd: Can not create a remote I/O target object, status: 0x%X\n",
535 WDF_IO_TARGET_OPEN_PARAMS_INIT_EXISTING_DEVICE(&ioTargetOpenParams
,
536 WdfDeviceWdmGetAttachedDevice(deviceExtension
->Device
));
538 status
= WdfIoTargetOpen(deviceExtension
->IoTarget
,
539 &ioTargetOpenParams
);
540 if (!NT_SUCCESS(status
))
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",
546 WdfObjectDelete(deviceExtension
->IoTarget
);
547 deviceExtension
->IoTarget
= NULL
;
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
);
558 if (!NT_SUCCESS(status
))
560 // Someone already had this device - we're in trouble
565 deviceClaimed
= TRUE
;
569 // CDROM Queueing Structure
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.
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.
581 // 10. Set up IO queues after device being created.
584 WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig
,
585 WdfIoQueueDispatchSequential
);
587 queueConfig
.PowerManaged
= WdfFalse
;
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
;
596 queueConfig
.EvtIoDeviceControl
= SequentialQueueEvtIoDeviceControl
;
597 queueConfig
.EvtIoCanceledOnQueue
= SequentialQueueEvtCanceledOnQueue
;
599 status
= WdfIoQueueCreate(device
,
601 WDF_NO_OBJECT_ATTRIBUTES
,
602 &(deviceExtension
->SerialIOQueue
));
603 if (!NT_SUCCESS(status
))
608 // this queue is dedicated for file create requests.
609 WDF_IO_QUEUE_CONFIG_INIT(&queueConfig
, WdfIoQueueDispatchParallel
);
611 queueConfig
.PowerManaged
= WdfFalse
;
612 queueConfig
.EvtIoDefault
= CreateQueueEvtIoDefault
;
614 //Reuse this structure.
615 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes
,
616 CDROM_REQUEST_CONTEXT
);
618 attributes
.SynchronizationScope
= WdfSynchronizationScopeNone
;
619 attributes
.ExecutionLevel
= WdfExecutionLevelPassive
;
621 status
= WdfIoQueueCreate(device
,
624 &(deviceExtension
->CreateQueue
));
626 if (!NT_SUCCESS(status
))
631 // Configure the device to use driver created queue for dispatching create.
632 status
= WdfDeviceConfigureRequestDispatching(device
,
633 deviceExtension
->CreateQueue
,
634 WdfRequestTypeCreate
);
636 if (!NT_SUCCESS(status
))
642 // 11. Set the alignment requirements for the device based on the host adapter requirements.
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
)
648 WdfDeviceSetAlignmentRequirement(deviceExtension
->Device
,
649 deviceExtension
->LowerPdo
->AlignmentRequirement
);
652 // 12. Initialization of miscellaneous internal properties
654 // CDROMs are not partitionable so starting offset is 0.
655 deviceExtension
->StartingOffset
.LowPart
= 0;
656 deviceExtension
->StartingOffset
.HighPart
= 0;
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;
665 deviceExtension
->DeviceAdditionalData
.ReadWriteRetryDelay100nsUnits
= WRITE_RETRY_DELAY_DVD_1x
;
667 // Clear the SrbFlags and disable synchronous transfers
668 deviceExtension
->SrbFlags
= SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
670 // Set timeout value in seconds.
671 deviceExtension
->TimeOutValue
= DeviceGetTimeOutValueFromRegistry();
672 if ((deviceExtension
->TimeOutValue
> 30 * 60) || // longer than 30 minutes
673 (deviceExtension
->TimeOutValue
== 0))
675 deviceExtension
->TimeOutValue
= SCSI_CDROM_TIMEOUT
;
678 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_INIT
,
679 "DriverEvtDeviceAdd: device timeout is set to %x seconds",
680 deviceExtension
->TimeOutValue
683 #if (NTDDI_VERSION >= NTDDI_WIN8)
684 deviceExtension
->IsVolumeOnlinePending
= TRUE
;
686 WDF_IO_QUEUE_CONFIG_INIT(&queueConfig
, WdfIoQueueDispatchManual
);
688 queueConfig
.PowerManaged
= WdfFalse
;
690 status
= WdfIoQueueCreate(device
,
692 WDF_NO_OBJECT_ATTRIBUTES
,
693 &deviceExtension
->ManualVolumeReadyQueue
);
695 if (!NT_SUCCESS(status
))
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
);
707 deviceExtension
->LockCount
= 0;
709 // 14. Initialize context structures needed for asynchronous release queue and power requests
711 if (NT_SUCCESS(status
))
713 status
= DeviceInitReleaseQueueContext(deviceExtension
);
716 if (NT_SUCCESS(status
))
718 status
= DeviceInitPowerContext(deviceExtension
);
721 // 15. Create external access points other than device name.
722 if (NT_SUCCESS(status
))
724 status
= DeviceCreateWellKnownName(deviceExtension
);
727 // 16. Query session id from the PDO.
728 if (NT_SUCCESS(status
))
730 status
= IoGetDevicePropertyData(deviceExtension
->LowerPdo
,
731 &DEVPKEY_Device_SessionId
,
734 sizeof(devicePropertySessionId
),
735 &devicePropertySessionId
,
737 &devicePropertyType
);
739 if (!NT_SUCCESS(status
))
741 // The device is global.
742 devicePropertySessionId
= INVALID_SESSION
;
743 status
= STATUS_SUCCESS
;
747 // 17. Register interfaces for this device.
748 if (NT_SUCCESS(status
))
750 status
= DeviceRegisterInterface(deviceExtension
, CdRomDeviceInterface
);
753 if (NT_SUCCESS(status
))
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
)
759 status
= DeviceRegisterInterface(deviceExtension
, MountedDeviceInterface
);
763 // 18. Initialize the shutdown/flush lock
764 if (NT_SUCCESS(status
))
766 WDF_OBJECT_ATTRIBUTES_INIT(&attributes
);
767 attributes
.ParentObject
= deviceExtension
->Device
;
769 status
= WdfWaitLockCreate(&attributes
, &deviceExtension
->ShutdownFlushWaitLock
);
770 if (!NT_SUCCESS(status
))
772 TracePrint((TRACE_LEVEL_FATAL
, TRACE_FLAG_PNP
,
773 "DriverEvtDeviceAdd: Cannot create shutdown/flush waitlock, status: 0x%X\n",
778 // 19. Initialize the work item that is used to initiate asynchronous reads/writes
779 if (NT_SUCCESS(status
))
781 WDF_WORKITEM_CONFIG workItemConfig
;
782 WDF_OBJECT_ATTRIBUTES workItemAttributes
;
784 WDF_WORKITEM_CONFIG_INIT(&workItemConfig
,
785 ReadWriteWorkItemRoutine
788 WDF_OBJECT_ATTRIBUTES_INIT(&workItemAttributes
);
789 workItemAttributes
.ParentObject
= deviceExtension
->Device
;
791 status
= WdfWorkItemCreate(&workItemConfig
,
793 &deviceExtension
->ReadWriteWorkItem
796 if (!NT_SUCCESS(status
))
798 TracePrint((TRACE_LEVEL_FATAL
, TRACE_FLAG_INIT
,
799 "DriverEvtDeviceAdd: Cannot create read/write work item, status: 0x%X\n",
804 // 20. Initialize the work item that is used to process most IOCTLs at PASSIVE_LEVEL.
805 if (NT_SUCCESS(status
))
807 WDF_WORKITEM_CONFIG workItemConfig
;
808 WDF_OBJECT_ATTRIBUTES workItemAttributes
;
810 WDF_WORKITEM_CONFIG_INIT(&workItemConfig
,
814 WDF_OBJECT_ATTRIBUTES_INIT(&workItemAttributes
);
815 workItemAttributes
.ParentObject
= deviceExtension
->Device
;
817 status
= WdfWorkItemCreate(&workItemConfig
,
819 &deviceExtension
->IoctlWorkItem
822 if (!NT_SUCCESS(status
))
824 TracePrint((TRACE_LEVEL_FATAL
, TRACE_FLAG_INIT
,
825 "DriverEvtDeviceAdd: Cannot create ioctl work item, status: 0x%X\n",
833 if (!NT_SUCCESS(status
))
835 FREE_POOL(wideDeviceName
);
837 if (deviceExtension
!= NULL
)
839 RtlInitUnicodeString(&deviceExtension
->DeviceName
, NULL
);
842 // Release the device with the port driver, if it was claimed
843 if ((deviceExtension
!= NULL
) && deviceClaimed
)
845 DeviceClaimRelease(deviceExtension
, TRUE
);
847 deviceClaimed
= FALSE
;
855 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
857 _In_ WDFOBJECT Device
862 Free all the resources allocated in DriverEvtDeviceAdd.
866 Device - handle to a WDF Device object.
874 WDFDEVICE device
= (WDFDEVICE
)Device
;
875 PCDROM_DEVICE_EXTENSION deviceExtension
= NULL
;
879 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_INIT
,
880 "WDFDEVICE %p cleanup: The device is about to be destroyed.\n",
883 deviceExtension
= DeviceGetExtension(device
);
885 FREE_POOL(deviceExtension
->DeviceName
.Buffer
);
886 RtlInitUnicodeString(&deviceExtension
->DeviceName
, NULL
);
888 if (deviceExtension
->DeviceAdditionalData
.WellKnownName
.Buffer
!= NULL
)
890 IoDeleteSymbolicLink(&deviceExtension
->DeviceAdditionalData
.WellKnownName
);
893 FREE_POOL(deviceExtension
->DeviceAdditionalData
.WellKnownName
.Buffer
);
894 RtlInitUnicodeString(&deviceExtension
->DeviceAdditionalData
.WellKnownName
, NULL
);
901 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
902 DeviceEvtSelfManagedIoCleanup(
903 _In_ WDFDEVICE Device
909 this function is called when the device is removed.
910 release the ownership of the device, release allocated resources.
914 Device - Handle to device object
923 PCDROM_DEVICE_EXTENSION deviceExtension
= NULL
;
927 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_PNP
,
928 "DeviceEvtSelfManagedIoCleanup: WDFDEVICE %p is being stopped.\n",
931 // extract the device and driver extensions
932 deviceExtension
= DeviceGetExtension(Device
);
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
);
939 // Close the IoTarget so that we are sure there are no outstanding I/Os in the stack.
940 if (deviceExtension
->IoTarget
)
942 WdfIoTargetClose(deviceExtension
->IoTarget
);
945 // Release the device
946 if (!deviceExtension
->SurpriseRemoved
)
948 status
= DeviceClaimRelease(deviceExtension
, TRUE
); //status is mainly for debugging. we don't really care.
949 UNREFERENCED_PARAMETER(status
); //defensive coding, avoid PREFAST warning.
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.
956 // Release all the memory that we have allocated.
958 DeviceDeallocateMmcResources(Device
);
959 ScratchBuffer_Deallocate(deviceExtension
);
960 RtlZeroMemory(&(deviceExtension
->DeviceAdditionalData
.Mmc
), sizeof(CDROM_MMC_EXTENSION
));
962 FREE_POOL(deviceExtension
->DeviceDescriptor
);
963 FREE_POOL(deviceExtension
->AdapterDescriptor
);
964 FREE_POOL(deviceExtension
->PowerDescriptor
);
965 FREE_POOL(deviceExtension
->SenseData
);
967 if (deviceExtension
->DeviceAdditionalData
.CachedInquiryData
!= NULL
)
969 FREE_POOL(deviceExtension
->DeviceAdditionalData
.CachedInquiryData
);
970 deviceExtension
->DeviceAdditionalData
.CachedInquiryDataByteCount
= 0;
973 FREE_POOL(deviceExtension
->PrivateFdoData
);
975 DeviceReleaseMcnResources(deviceExtension
);
977 DeviceReleaseZPODDResources(deviceExtension
);
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
--;
983 deviceExtension
->PartitionLength
.QuadPart
= 0;
985 // All WDF objects related to Device will be automatically released
986 // when the root object is deleted. No need to release them manually.
992 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
994 _In_ WDFDEVICE Device
,
995 _In_ WDF_POWER_DEVICE_STATE PreviousState
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.
1006 Device - Handle to device object
1007 PreviousState - Power state the device was in.
1011 NTSTATUS: alway STATUS_SUCCESS
1015 PCDROM_DEVICE_EXTENSION deviceExtension
;
1016 NTSTATUS status
= STATUS_SUCCESS
;
1017 PZERO_POWER_ODD_INFO zpoddInfo
= NULL
;
1018 STORAGE_IDLE_POWERUP_REASON powerupReason
= {0};
1020 UNREFERENCED_PARAMETER(PreviousState
);
1021 deviceExtension
= DeviceGetExtension(Device
);
1023 // Make certain not to do anything before properly initialized
1024 if (deviceExtension
->IsInitialized
)
1026 zpoddInfo
= deviceExtension
->ZeroPowerODDInfo
;
1028 if (zpoddInfo
!= NULL
)
1030 if (zpoddInfo
->InZeroPowerState
!= FALSE
)
1032 // We just woke up from Zero Power state
1033 zpoddInfo
->InZeroPowerState
= FALSE
;
1034 zpoddInfo
->RetryFirstCommand
= TRUE
;
1035 zpoddInfo
->BecomingReadyRetryCount
= BECOMING_READY_RETRY_COUNT
;
1037 status
= DeviceZPODDGetPowerupReason(deviceExtension
, &powerupReason
);
1039 if (NT_SUCCESS(status
) &&
1040 (powerupReason
.PowerupReason
== StoragePowerupDeviceAttention
))
1042 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_POWER
,
1043 "DeviceEvtD0Entry: Device has left zero power state due to eject button pressed\n"
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
1053 DeviceSendIoctlAsynchronously(deviceExtension
, IOCTL_STORAGE_EJECT_MEDIA
, deviceExtension
->DeviceObject
);
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"
1067 DeviceEnableMainTimer(deviceExtension
);
1070 return STATUS_SUCCESS
;
1074 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
1076 _In_ WDFDEVICE Device
,
1077 _In_ WDF_POWER_DEVICE_STATE TargetState
1081 Routine Description:
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.
1089 Device - Handle to device object
1090 TargetState - Power state the device is entering.
1094 NTSTATUS: alway STATUS_SUCCESS
1098 NTSTATUS status
= STATUS_SUCCESS
;
1099 PCDROM_DEVICE_EXTENSION deviceExtension
= NULL
;
1100 PZERO_POWER_ODD_INFO zpoddInfo
= NULL
;
1104 deviceExtension
= DeviceGetExtension(Device
);
1105 zpoddInfo
= deviceExtension
->ZeroPowerODDInfo
;
1107 // we only process the situation that the device is going into D3.
1108 if ((TargetState
!= WdfPowerDeviceD3
) &&
1109 (TargetState
!= WdfPowerDeviceD3Final
))
1111 return STATUS_SUCCESS
;
1114 // Stop the main timer
1115 DeviceDisableMainTimer(deviceExtension
);
1117 // note: do not stop CreateQueue as the create request can be handled by port driver even the device is in D3 status.
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
)
1123 return STATUS_SUCCESS
;
1128 #if (WINVER >= 0x0601)
1129 // this API is introduced in Windows7
1131 ULONG secondsRemaining
= 0;
1132 BOOLEAN watchdogTimeSupported
= FALSE
;
1134 watchdogTimeSupported
= PoQueryWatchdogTime(deviceExtension
->LowerPdo
, &secondsRemaining
);
1135 UNREFERENCED_PARAMETER(watchdogTimeSupported
);
1140 deviceExtension
->PowerDownInProgress
= TRUE
;
1142 status
= PowerContextBeginUse(deviceExtension
);
1144 deviceExtension
->PowerContext
.Options
.PowerDown
= TRUE
;
1146 // Step 1. LOCK QUEUE
1147 if (NT_SUCCESS(status
) &&
1148 (TargetState
!= WdfPowerDeviceD3Final
))
1150 status
= DeviceSendPowerDownProcessRequest(deviceExtension
, NULL
, NULL
);
1152 if (NT_SUCCESS(status
))
1154 deviceExtension
->PowerContext
.Options
.LockQueue
= TRUE
;
1158 status
= STATUS_SUCCESS
;
1161 deviceExtension
->PowerContext
.PowerChangeState
.PowerDown
++;
1163 // Step 2. QUIESCE QUEUE
1164 if (NT_SUCCESS(status
) &&
1165 (TargetState
!= WdfPowerDeviceD3Final
))
1167 status
= DeviceSendPowerDownProcessRequest(deviceExtension
, NULL
, NULL
);
1168 UNREFERENCED_PARAMETER(status
);
1169 // We don't care about the status.
1170 status
= STATUS_SUCCESS
;
1173 deviceExtension
->PowerContext
.PowerChangeState
.PowerDown
++;
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
)
1179 status
= DeviceSendPowerDownProcessRequest(deviceExtension
, NULL
, NULL
);
1180 UNREFERENCED_PARAMETER(status
);
1181 status
= STATUS_SUCCESS
;
1184 deviceExtension
->PowerContext
.PowerChangeState
.PowerDown
++;
1186 // Step 4. STOP UNIT
1187 if (NT_SUCCESS(status
) &&
1188 !TEST_FLAG(deviceExtension
->ScanForSpecialFlags
, CDROM_SPECIAL_DISABLE_SPIN_DOWN
))
1190 status
= DeviceSendPowerDownProcessRequest(deviceExtension
, NULL
, NULL
);
1191 UNREFERENCED_PARAMETER(status
);
1192 status
= STATUS_SUCCESS
;
1195 if (TargetState
== WdfPowerDeviceD3Final
)
1197 // We're done with the power context.
1198 PowerContextEndUse(deviceExtension
);
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
);
1205 // If this power down is caused by Zero Power ODD, we should mark the device as in ZPODD mode.
1206 if (zpoddInfo
!= NULL
)
1208 zpoddInfo
->InZeroPowerState
= TRUE
;
1210 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_POWER
,
1211 "Device has entered zero power state\n"
1215 deviceExtension
->PowerDownInProgress
= FALSE
;
1217 return STATUS_SUCCESS
;
1222 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
1223 DeviceEvtSurpriseRemoval(
1224 _In_ WDFDEVICE Device
1228 Routine Description:
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.
1235 Device - Handle to device object
1243 PCDROM_DEVICE_EXTENSION deviceExtension
= NULL
;
1247 deviceExtension
= DeviceGetExtension(Device
);
1249 deviceExtension
->SurpriseRemoved
= TRUE
;
1251 // Stop the main timer
1252 DeviceDisableMainTimer(deviceExtension
);
1254 // legacy behavior to set partition length to be 0.
1255 deviceExtension
->PartitionLength
.QuadPart
= 0;
1257 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_INIT
,
1258 "Surprisely remove a WDFDEVICE %p\n", Device
));
1265 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
1266 CreateQueueEvtIoDefault(
1267 _In_ WDFQUEUE Queue
,
1268 _In_ WDFREQUEST Request
1272 Routine Description:
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.
1279 Queue - Handle to device queue
1281 Request - the creation request
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
;
1297 if (fileObject
== NULL
) {
1299 TracePrint((TRACE_LEVEL_ERROR
, TRACE_FLAG_QUEUE
,
1300 "Error: received a file create request with file object set to NULL\n"));
1302 RequestCompletion(deviceExtension
, Request
, STATUS_INTERNAL_ERROR
, 0);
1306 fileObjectContext
= FileObjectGetContext(fileObject
);
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
;
1316 // send down the create synchronously
1317 status
= DeviceSendRequestSynchronously(device
, Request
, FALSE
);
1319 // Need to complete the request in this routine.
1320 RequestCompletion(deviceExtension
, Request
, status
, WdfRequestGetInformation(Request
));
1326 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
1328 _In_ WDFFILEOBJECT FileObject
1332 Routine Description:
1334 this function is called when CLOSE irp comes.
1335 clean up MCN / Lock if necessary
1339 FileObject - WDF file object created for the irp.
1347 NTSTATUS status
= STATUS_SUCCESS
;
1351 if (FileObject
!= NULL
)
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
);
1358 // cleanup locked media tray
1359 status
= DeviceCleanupProtectedLocks(deviceExtension
, fileObjectContext
);
1360 if (!NT_SUCCESS(status
))
1362 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_INIT
,
1363 "Failed to cleanup protected locks for WDFDEVICE %p, %!STATUS!\n", device
, status
));
1366 // cleanup disabled MCN
1367 status
= DeviceCleanupDisableMcn(deviceExtension
, fileObjectContext
);
1368 if (!NT_SUCCESS(status
))
1370 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_INIT
,
1371 "Failed to disable MCN for WDFDEVICE %p, %!STATUS!\n", device
, status
));
1374 // cleanup exclusive access
1375 if (EXCLUSIVE_MODE(cdData
) && EXCLUSIVE_OWNER(cdData
, FileObject
))
1377 status
= DeviceUnlockExclusive(deviceExtension
, FileObject
, FALSE
);
1378 if (!NT_SUCCESS(status
))
1380 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_INIT
,
1381 "Failed to release exclusive lock for WDFDEVICE %p, %!STATUS!\n", device
, status
));
1389 _IRQL_requires_max_(PASSIVE_LEVEL
)
1391 DeviceCleanupProtectedLocks(
1392 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
,
1393 _In_ PFILE_OBJECT_CONTEXT FileObjectContext
1397 Routine Description:
1399 this function removes protected locks for the handle
1403 DeviceExtension - device context
1405 FileObject - WDF file object created for the irp.
1413 NTSTATUS status
= STATUS_SUCCESS
;
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
));
1421 // Synchronize with ejection and ejection control requests.
1422 WdfWaitLockAcquire(DeviceExtension
->EjectSynchronizationLock
, NULL
);
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)
1428 DeviceExtension
->ProtectedLockCount
-= FileObjectContext
->LockCount
;
1429 FileObjectContext
->LockCount
= 0;
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
));
1439 if ((DeviceExtension
->ProtectedLockCount
== 0) && (DeviceExtension
->LockCount
== 0))
1441 SCSI_REQUEST_BLOCK srb
= {0};
1442 PCDB cdb
= (PCDB
) &(srb
.Cdb
);
1446 cdb
->MEDIA_REMOVAL
.OperationCode
= SCSIOP_MEDIUM_REMOVAL
;
1448 // TRUE - prevent media removal.
1449 // FALSE - allow media removal.
1450 cdb
->MEDIA_REMOVAL
.Prevent
= FALSE
;
1452 // Set timeout value.
1453 srb
.TimeOutValue
= DeviceExtension
->TimeOutValue
;
1454 status
= DeviceSendSrbSynchronously(DeviceExtension
->Device
,
1461 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_INIT
,
1462 "Allow media removal (unlock) request to drive returned %!STATUS!\n",
1467 WdfWaitLockRelease(DeviceExtension
->EjectSynchronizationLock
);
1473 _IRQL_requires_max_(APC_LEVEL
)
1475 DeviceCleanupDisableMcn(
1476 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
,
1477 _In_ PFILE_OBJECT_CONTEXT FileObjectContext
1481 Routine Description:
1483 cleanup the MCN disable count for the handle
1487 DeviceExtension - device context
1489 FileObject - WDF file object created for the irp.
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
));
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)
1507 DeviceEnableMediaChangeDetection(DeviceExtension
, FileObjectContext
, TRUE
);
1510 return STATUS_SUCCESS
;
1515 _Inout_ PWDF_REQUEST_PARAMETERS requestParameters
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.
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;
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.
1538 if((functionCode
>= 0x200) && (functionCode
<= 0x300))
1540 ioctlCode
= (ioctlCode
& 0x0000ffff) | CTL_CODE(IOCTL_STORAGE_BASE
, 0, 0, 0);
1542 TracePrint((TRACE_LEVEL_VERBOSE
, TRACE_FLAG_IOCTL
,
1543 "IOCTL code recalibrate, New ioctl code is %lx\n",
1546 // Set the code into request parameters, then "requestParameters" needs to be used for dispatch functions.
1547 requestParameters
->Parameters
.DeviceIoControl
.IoControlCode
= ioctlCode
;
1553 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
1554 DeviceEvtIoInCallerContext(
1555 _In_ WDFDEVICE Device
,
1556 _In_ WDFREQUEST Request
1559 Routine Description:
1561 Responds to EvtIoInCallerContext events from KMDF
1562 It calls different functions to process different type of IOCTLs.
1566 Device - handle to a WDF Device object
1568 Request - handle to the incoming WDF Request object
1576 NTSTATUS status
= STATUS_SUCCESS
;
1577 PCDROM_DEVICE_EXTENSION deviceExtension
= DeviceGetExtension(Device
);
1578 PCDROM_REQUEST_CONTEXT requestContext
= RequestGetContext(Request
);
1579 WDF_REQUEST_PARAMETERS requestParameters
;
1581 requestContext
->DeviceExtension
= deviceExtension
;
1583 // set the received time
1584 RequestSetReceivedTime(Request
);
1586 // get the request parameters
1587 WDF_REQUEST_PARAMETERS_INIT(&requestParameters
);
1588 WdfRequestGetParameters(Request
, &requestParameters
);
1590 if (requestParameters
.Type
== WdfRequestTypeDeviceControl
)
1592 BOOLEAN processed
= FALSE
;
1593 PCDROM_DATA cdData
= &(deviceExtension
->DeviceAdditionalData
);
1594 PMEDIA_CHANGE_DETECTION_INFO info
= deviceExtension
->MediaChangeDetectionInfo
;
1596 if (requestParameters
.Parameters
.DeviceIoControl
.IoControlCode
!= IOCTL_MCN_SYNC_FAKE_IOCTL
)
1598 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
1599 "Receiving IOCTL: %lx\n",
1600 requestParameters
.Parameters
.DeviceIoControl
.IoControlCode
));
1604 TracePrint((TRACE_LEVEL_VERBOSE
, TRACE_FLAG_IOCTL
,
1605 "Receiving IOCTL: %lx\n",
1606 requestParameters
.Parameters
.DeviceIoControl
.IoControlCode
));
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
)))
1613 BOOLEAN isBlocked
= FALSE
;
1615 status
= RequestIsIoctlBlockedByExclusiveAccess(Request
, &isBlocked
);
1616 UNREFERENCED_PARAMETER(status
); //defensive coding, avoid PREFAST warning.
1620 if ((requestParameters
.Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_STORAGE_EVENT_NOTIFICATION
) &&
1621 (info
!= NULL
) && (info
->AsynchronousNotificationSupported
!= FALSE
))
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
;
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);
1639 NormalizeIoctl(&requestParameters
);
1641 // 1. All requests that don't need to access device can be processed immediately
1644 processed
= RequestDispatchProcessDirectly(Device
, Request
, requestParameters
);
1647 // 2. Requests that should be put in sequential queue.
1650 processed
= RequestDispatchToSequentialQueue(Device
, Request
, requestParameters
);
1653 // 3. Requests that need to be processed sequentially and in caller's context.
1656 processed
= RequestDispatchSyncWithSequentialQueue(Device
, Request
, requestParameters
);
1659 // 4. Special requests that needs different process in different cases.
1662 processed
= RequestDispatchSpecialIoctls(Device
, Request
, requestParameters
);
1665 // 5. This is default behavior for unknown IOCTLs. To pass it to lower level.
1668 processed
= RequestDispatchUnknownRequests(Device
, Request
, requestParameters
);
1671 // All requests should be processed already.
1672 NT_ASSERT(processed
);
1673 UNREFERENCED_PARAMETER(processed
); //defensive coding, avoid PREFAST warning.
1675 else if (requestParameters
.Type
== WdfRequestTypeDeviceControlInternal
)
1677 RequestProcessInternalDeviceControl(Request
, deviceExtension
);
1681 // Requests other than IOCTLs will be forwarded to default queue.
1682 status
= WdfDeviceEnqueueRequest(Device
, Request
);
1683 if (!NT_SUCCESS(status
))
1685 RequestCompletion(deviceExtension
, Request
, status
, WdfRequestGetInformation(Request
));
1694 RequestDispatchProcessDirectly(
1695 _In_ WDFDEVICE Device
,
1696 _In_ WDFREQUEST Request
,
1697 _In_ WDF_REQUEST_PARAMETERS RequestParameters
1700 Routine Description:
1702 These requests can be processed in a non-serialized manner, most of them don't need to access device.
1706 Device - handle to a WDF Device object
1708 Request - handle to the incoming WDF Request object
1710 RequestParameters - request parameters
1714 BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function).
1718 NTSTATUS status
= STATUS_SUCCESS
;
1719 BOOLEAN processed
= FALSE
;
1720 size_t dataLength
= 0;
1722 PCDROM_DEVICE_EXTENSION deviceExtension
= DeviceGetExtension(Device
);
1723 ULONG ioctlCode
= RequestParameters
.Parameters
.DeviceIoControl
.IoControlCode
;
1728 case IOCTL_CDROM_GET_INQUIRY_DATA
:
1730 status
= RequestHandleGetInquiryData(deviceExtension
, Request
, RequestParameters
, &dataLength
);
1733 break; // complete the irp
1736 case IOCTL_STORAGE_GET_MEDIA_TYPES_EX
:
1738 status
= RequestHandleGetMediaTypeEx(deviceExtension
, Request
, &dataLength
);
1741 break; // complete the irp
1744 case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
:
1746 status
= RequestHandleMountQueryUniqueId(deviceExtension
, Request
, RequestParameters
, &dataLength
);
1749 break; // complete the irp
1752 case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
:
1754 status
= RequestHandleMountQueryDeviceName(deviceExtension
, Request
, RequestParameters
, &dataLength
);
1757 break; // complete the irp
1760 case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME
:
1762 status
= RequestHandleMountQuerySuggestedLinkName(deviceExtension
, Request
, RequestParameters
, &dataLength
);
1765 break; // complete the irp
1768 case IOCTL_STORAGE_GET_DEVICE_NUMBER
:
1770 status
= RequestHandleGetDeviceNumber(deviceExtension
, Request
, RequestParameters
, &dataLength
);
1773 break; // complete the irp
1776 case IOCTL_STORAGE_GET_HOTPLUG_INFO
:
1778 status
= RequestHandleGetHotPlugInfo(deviceExtension
, Request
, RequestParameters
, &dataLength
);
1781 break; // complete the irp
1784 case IOCTL_STORAGE_SET_HOTPLUG_INFO
:
1786 status
= RequestHandleSetHotPlugInfo(deviceExtension
, Request
, RequestParameters
, &dataLength
);
1789 break; // complete the irp
1792 case IOCTL_STORAGE_EVENT_NOTIFICATION
:
1794 status
= RequestHandleEventNotification(deviceExtension
, Request
, &RequestParameters
, &dataLength
);
1797 break; // complete the irp
1800 #if (NTDDI_VERSION >= NTDDI_WIN8)
1801 case IOCTL_VOLUME_ONLINE
:
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
1812 if (WdfRequestGetRequestorMode(Request
) == KernelMode
)
1826 } //end of switch (ioctlCode)
1830 UCHAR currentStackLocationFlags
= 0;
1831 currentStackLocationFlags
= RequestGetCurrentStackLocationFlags(Request
);
1833 if ((status
== STATUS_VERIFY_REQUIRED
) &&
1834 (currentStackLocationFlags
& SL_OVERRIDE_VERIFY_VOLUME
))
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...
1841 processed
= RequestDispatchProcessDirectly(Device
, Request
, RequestParameters
);
1845 // Complete the request after processing it.
1846 RequestCompletion(deviceExtension
, Request
, status
, dataLength
);
1855 RequestDispatchToSequentialQueue(
1856 _In_ WDFDEVICE Device
,
1857 _In_ WDFREQUEST Request
,
1858 _In_ WDF_REQUEST_PARAMETERS RequestParameters
1861 Routine Description:
1863 These requests can be processed in a non-serialized manner, most of them don't need to access device.
1867 Device - handle to a WDF Device object
1869 Request - handle to the incoming WDF Request object
1871 RequestParameters - request parameters
1875 BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function).
1879 NTSTATUS status
= STATUS_SUCCESS
;
1880 BOOLEAN processed
= FALSE
;
1881 size_t dataLength
= 0;
1882 BOOLEAN inZeroPowerState
= FALSE
;
1884 PCDROM_DEVICE_EXTENSION deviceExtension
= DeviceGetExtension(Device
);
1885 ULONG ioctlCode
= RequestParameters
.Parameters
.DeviceIoControl
.IoControlCode
;
1886 PZERO_POWER_ODD_INFO zpoddInfo
= deviceExtension
->ZeroPowerODDInfo
;
1888 if ((zpoddInfo
!= NULL
) &&
1889 (zpoddInfo
->InZeroPowerState
!= FALSE
))
1891 inZeroPowerState
= TRUE
;
1897 case IOCTL_CDROM_RAW_READ
:
1899 status
= RequestValidateRawRead(deviceExtension
, Request
, RequestParameters
, &dataLength
);
1905 case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
:
1906 case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX
:
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
))
1913 status
= STATUS_BUFFER_TOO_SMALL
;
1914 dataLength
= FIELD_OFFSET(DISK_GEOMETRY_EX
, Data
);
1916 else if (inZeroPowerState
!= FALSE
)
1918 status
= STATUS_NO_MEDIA_IN_DEVICE
;
1922 status
= STATUS_SUCCESS
;
1929 case IOCTL_DISK_GET_DRIVE_GEOMETRY
:
1930 case IOCTL_CDROM_GET_DRIVE_GEOMETRY
:
1932 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
1933 "RequestDispatchToSequentialQueue: Get drive geometry\n"));
1934 if (RequestParameters
.Parameters
.DeviceIoControl
.OutputBufferLength
<
1935 sizeof(DISK_GEOMETRY
))
1937 status
= STATUS_BUFFER_TOO_SMALL
;
1938 dataLength
= sizeof(DISK_GEOMETRY
);
1940 else if (inZeroPowerState
!= FALSE
)
1942 status
= STATUS_NO_MEDIA_IN_DEVICE
;
1946 status
= STATUS_SUCCESS
;
1953 case IOCTL_CDROM_READ_TOC_EX
:
1955 status
= RequestValidateReadTocEx(deviceExtension
, Request
, RequestParameters
, &dataLength
);
1957 if (inZeroPowerState
!= FALSE
)
1959 status
= STATUS_NO_MEDIA_IN_DEVICE
;
1966 case IOCTL_CDROM_READ_TOC
:
1968 status
= RequestValidateReadToc(deviceExtension
, RequestParameters
, &dataLength
);
1970 if (inZeroPowerState
!= FALSE
)
1972 status
= STATUS_NO_MEDIA_IN_DEVICE
;
1979 case IOCTL_CDROM_GET_LAST_SESSION
:
1981 status
= RequestValidateGetLastSession(deviceExtension
, RequestParameters
, &dataLength
);
1987 case IOCTL_CDROM_PLAY_AUDIO_MSF
:
1989 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
1990 "RequestDispatchToSequentialQueue: Play audio MSF\n"));
1992 if (RequestParameters
.Parameters
.DeviceIoControl
.InputBufferLength
<
1993 sizeof(CDROM_PLAY_AUDIO_MSF
))
1995 status
= STATUS_INFO_LENGTH_MISMATCH
;
1999 status
= STATUS_SUCCESS
;
2006 case IOCTL_CDROM_SEEK_AUDIO_MSF
:
2008 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2009 "RequestDispatchToSequentialQueue: Seek audio MSF\n"));
2011 if (RequestParameters
.Parameters
.DeviceIoControl
.InputBufferLength
<
2012 sizeof(CDROM_SEEK_AUDIO_MSF
))
2014 status
= STATUS_INFO_LENGTH_MISMATCH
;
2018 status
= STATUS_SUCCESS
;
2025 case IOCTL_CDROM_PAUSE_AUDIO
:
2027 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2028 "RequestDispatchToSequentialQueue: Pause audio\n"));
2030 status
= STATUS_SUCCESS
;
2035 case IOCTL_CDROM_RESUME_AUDIO
:
2037 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2038 "RequestDispatchToSequentialQueue: Resume audio\n"));
2040 status
= STATUS_SUCCESS
;
2045 case IOCTL_CDROM_READ_Q_CHANNEL
:
2047 status
= RequestValidateReadQChannel(Request
, RequestParameters
, &dataLength
);
2053 case IOCTL_CDROM_GET_VOLUME
:
2055 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2056 "RequestDispatchToSequentialQueue: Get volume control\n"));
2058 if (RequestParameters
.Parameters
.DeviceIoControl
.OutputBufferLength
<
2059 sizeof(VOLUME_CONTROL
))
2061 status
= STATUS_BUFFER_TOO_SMALL
;
2062 dataLength
= sizeof(VOLUME_CONTROL
);
2066 status
= STATUS_SUCCESS
;
2073 case IOCTL_CDROM_SET_VOLUME
:
2075 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2076 "RequestDispatchToSequentialQueue: Set volume control\n"));
2078 if (RequestParameters
.Parameters
.DeviceIoControl
.InputBufferLength
<
2079 sizeof(VOLUME_CONTROL
))
2081 status
= STATUS_INFO_LENGTH_MISMATCH
;
2085 status
= STATUS_SUCCESS
;
2092 case IOCTL_CDROM_STOP_AUDIO
:
2094 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2095 "RequestDispatchToSequentialQueue: Stop audio\n"));
2097 status
= STATUS_SUCCESS
;
2102 case IOCTL_STORAGE_CHECK_VERIFY
:
2103 case IOCTL_STORAGE_CHECK_VERIFY2
:
2105 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2106 "RequestDispatchToSequentialQueue: [%p] Check Verify\n", Request
));
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
)))
2113 status
= STATUS_BUFFER_TOO_SMALL
;
2114 dataLength
= sizeof(ULONG
);
2116 else if (inZeroPowerState
!= FALSE
)
2118 status
= STATUS_NO_MEDIA_IN_DEVICE
;
2122 status
= STATUS_SUCCESS
;
2129 case IOCTL_DVD_GET_REGION
:
2131 // validation will be done when process it.
2132 status
= STATUS_SUCCESS
;
2137 case IOCTL_DVD_READ_STRUCTURE
:
2139 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2140 "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_READ_STRUCTURE\n", Request
));
2142 status
= RequestValidateDvdReadStructure(deviceExtension
, RequestParameters
, &dataLength
);
2148 case IOCTL_DVD_READ_KEY
:
2150 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2151 "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_READ_KEY\n", Request
));
2153 status
= RequestValidateDvdReadKey(deviceExtension
, Request
, RequestParameters
, &dataLength
);
2159 case IOCTL_DVD_START_SESSION
:
2161 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2162 "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_START_SESSION\n", Request
));
2164 status
= RequestValidateDvdStartSession(deviceExtension
, RequestParameters
, &dataLength
);
2170 case IOCTL_DVD_SEND_KEY
:
2171 case IOCTL_DVD_SEND_KEY2
:
2173 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2174 "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_SEND_KEY\n", Request
));
2176 status
= RequestValidateDvdSendKey(deviceExtension
, Request
, RequestParameters
, &dataLength
);
2182 case IOCTL_STORAGE_SET_READ_AHEAD
:
2184 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2185 "RequestDispatchToSequentialQueue: [%p] SetReadAhead\n", Request
));
2187 if (RequestParameters
.Parameters
.DeviceIoControl
.InputBufferLength
<
2188 sizeof(STORAGE_SET_READ_AHEAD
))
2190 status
= STATUS_INVALID_PARAMETER
;
2194 status
= STATUS_SUCCESS
;
2201 case IOCTL_DISK_IS_WRITABLE
:
2203 status
= STATUS_SUCCESS
;
2209 case IOCTL_DISK_GET_DRIVE_LAYOUT
:
2211 ULONG requiredSize
= 0;
2213 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2214 "RequestDispatchToSequentialQueue: Get drive layout\n"));
2216 requiredSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
, PartitionEntry
[1]);
2218 if (RequestParameters
.Parameters
.DeviceIoControl
.OutputBufferLength
<
2221 status
= STATUS_BUFFER_TOO_SMALL
;
2222 dataLength
= requiredSize
;
2226 status
= STATUS_SUCCESS
;
2233 case IOCTL_DISK_GET_DRIVE_LAYOUT_EX
:
2235 ULONG requiredSize
= 0;
2237 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2238 "RequestDispatchToSequentialQueue: Get drive layoutEx\n"));
2240 requiredSize
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX
, PartitionEntry
[1]);
2242 if (RequestParameters
.Parameters
.DeviceIoControl
.OutputBufferLength
<
2245 status
= STATUS_BUFFER_TOO_SMALL
;
2246 dataLength
= requiredSize
;
2250 status
= STATUS_SUCCESS
;
2257 case IOCTL_DISK_GET_PARTITION_INFO
:
2259 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2260 "RequestDispatchToSequentialQueue: Get Partition Info\n"));
2262 if (RequestParameters
.Parameters
.DeviceIoControl
.OutputBufferLength
<
2263 sizeof(PARTITION_INFORMATION
))
2265 status
= STATUS_BUFFER_TOO_SMALL
;
2266 dataLength
= sizeof(PARTITION_INFORMATION
);
2270 status
= STATUS_SUCCESS
;
2277 case IOCTL_DISK_GET_PARTITION_INFO_EX
:
2279 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2280 "RequestDispatchToSequentialQueue: Get Partition InfoEx\n"));
2282 if (RequestParameters
.Parameters
.DeviceIoControl
.OutputBufferLength
<
2283 sizeof(PARTITION_INFORMATION_EX
))
2285 status
= STATUS_BUFFER_TOO_SMALL
;
2286 dataLength
= sizeof(PARTITION_INFORMATION_EX
);
2290 status
= STATUS_SUCCESS
;
2297 case IOCTL_DISK_VERIFY
:
2299 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2300 "RequestDispatchToSequentialQueue: IOCTL_DISK_VERIFY to device %p through request %p\n",
2304 if (RequestParameters
.Parameters
.DeviceIoControl
.InputBufferLength
<
2305 sizeof(VERIFY_INFORMATION
))
2307 status
= STATUS_INVALID_PARAMETER
;
2311 status
= STATUS_SUCCESS
;
2318 case IOCTL_DISK_GET_LENGTH_INFO
:
2320 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2321 "RequestDispatchToSequentialQueue: Disk Get Length InfoEx\n"));
2323 if (RequestParameters
.Parameters
.DeviceIoControl
.OutputBufferLength
<
2324 sizeof(GET_LENGTH_INFORMATION
))
2326 status
= STATUS_BUFFER_TOO_SMALL
;
2327 dataLength
= sizeof(GET_LENGTH_INFORMATION
);
2329 else if (inZeroPowerState
!= FALSE
)
2331 status
= STATUS_NO_MEDIA_IN_DEVICE
;
2335 status
= STATUS_SUCCESS
;
2342 case IOCTL_CDROM_GET_CONFIGURATION
:
2344 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2345 "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_GET_CONFIGURATION\n", Request
));
2347 status
= RequestValidateGetConfiguration(deviceExtension
, Request
, RequestParameters
, &dataLength
);
2353 case IOCTL_CDROM_SET_SPEED
:
2355 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2356 "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_SET_SPEED\n", Request
));
2358 status
= RequestValidateSetSpeed(deviceExtension
, Request
, RequestParameters
, &dataLength
);
2364 case IOCTL_DVD_END_SESSION
:
2366 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2367 "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_END_SESSION\n", Request
));
2369 status
= RequestValidateDvdEndSession(deviceExtension
, Request
, RequestParameters
, &dataLength
);
2375 case IOCTL_AACS_END_SESSION
:
2377 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2378 "RequestDispatchToSequentialQueue: [%p] IOCTL_AACS_END_SESSION\n", Request
));
2380 status
= RequestValidateAacsEndSession(deviceExtension
, Request
, RequestParameters
, &dataLength
);
2386 case IOCTL_AACS_READ_MEDIA_KEY_BLOCK
:
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
2393 status
= RequestValidateAacsReadMediaKeyBlock(deviceExtension
, Request
, RequestParameters
, &dataLength
);
2399 case IOCTL_AACS_START_SESSION
:
2401 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_IOCTL
,
2402 "AACS: Requesting AGID\n"
2405 status
= RequestValidateAacsStartSession(deviceExtension
, RequestParameters
, &dataLength
);
2411 case IOCTL_AACS_SEND_CERTIFICATE
:
2413 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_IOCTL
,
2414 "AACS: Sending host certificate to drive\n"
2417 status
= RequestValidateAacsSendCertificate(deviceExtension
, Request
, RequestParameters
, &dataLength
);
2423 case IOCTL_AACS_GET_CERTIFICATE
:
2425 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_IOCTL
,
2426 "AACS: Querying drive certificate\n"
2429 status
= RequestValidateAacsGetCertificate(deviceExtension
, Request
, RequestParameters
, &dataLength
);
2435 case IOCTL_AACS_GET_CHALLENGE_KEY
:
2437 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_IOCTL
,
2438 "AACS: Querying drive challenge key\n"
2441 status
= RequestValidateAacsGetChallengeKey(deviceExtension
, Request
, RequestParameters
, &dataLength
);
2447 case IOCTL_AACS_SEND_CHALLENGE_KEY
:
2449 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_IOCTL
,
2450 "AACS: Sending drive challenge key\n"
2453 status
= RequestValidateAacsSendChallengeKey(deviceExtension
, Request
, RequestParameters
, &dataLength
);
2459 case IOCTL_AACS_READ_VOLUME_ID
:
2461 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_IOCTL
,
2462 "AACS: Reading volume ID\n"
2465 status
= RequestValidateAacsReadVolumeId(deviceExtension
, Request
, RequestParameters
, &dataLength
);
2471 case IOCTL_AACS_READ_SERIAL_NUMBER
:
2473 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_IOCTL
,
2474 "AACS: Reading Serial Number\n"
2477 status
= RequestValidateAacsReadSerialNumber(deviceExtension
, Request
, RequestParameters
, &dataLength
);
2483 case IOCTL_AACS_READ_MEDIA_ID
:
2485 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_IOCTL
,
2486 "AACS: Reading media ID\n"
2489 status
= RequestValidateAacsReadMediaId(deviceExtension
, Request
, RequestParameters
, &dataLength
);
2495 case IOCTL_AACS_READ_BINDING_NONCE
:
2496 case IOCTL_AACS_GENERATE_BINDING_NONCE
:
2498 if (ioctlCode
== IOCTL_AACS_GENERATE_BINDING_NONCE
)
2500 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_IOCTL
,
2501 "AACS: Generating new binding nonce\n"
2506 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_IOCTL
,
2507 "AACS: Reading existing binding nonce\n"
2511 status
= RequestValidateAacsBindingNonce(deviceExtension
, Request
, RequestParameters
, &dataLength
);
2517 case IOCTL_CDROM_ENABLE_STREAMING
:
2519 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2520 "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_ENABLE_STREAMING\n", Request
));
2522 status
= RequestValidateEnableStreaming(Request
, RequestParameters
, &dataLength
);
2528 case IOCTL_CDROM_SEND_OPC_INFORMATION
:
2530 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2531 "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_SEND_OPC_INFORMATION\n", Request
));
2533 status
= RequestValidateSendOpcInformation(Request
, RequestParameters
, &dataLength
);
2539 case IOCTL_CDROM_GET_PERFORMANCE
:
2541 TracePrint((TRACE_LEVEL_INFORMATION
, TRACE_FLAG_IOCTL
,
2542 "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_GET_PERFORMANCE\n", Request
));
2544 status
= RequestValidateGetPerformance(Request
, RequestParameters
, &dataLength
);
2550 case IOCTL_STORAGE_MEDIA_REMOVAL
:
2551 case IOCTL_STORAGE_EJECTION_CONTROL
:
2553 if(RequestParameters
.Parameters
.DeviceIoControl
.InputBufferLength
<
2554 sizeof(PREVENT_MEDIA_REMOVAL
))
2556 status
= STATUS_INFO_LENGTH_MISMATCH
;
2560 status
= STATUS_SUCCESS
;
2564 break; // complete the irp
2567 case IOCTL_STORAGE_MCN_CONTROL
:
2569 if(RequestParameters
.Parameters
.DeviceIoControl
.InputBufferLength
<
2570 sizeof(PREVENT_MEDIA_REMOVAL
))
2572 status
= STATUS_INFO_LENGTH_MISMATCH
;
2576 status
= STATUS_SUCCESS
;
2580 break; // complete the irp
2583 case IOCTL_STORAGE_RESERVE
:
2584 case IOCTL_STORAGE_RELEASE
:
2586 // there is no validate check currently.
2587 status
= STATUS_SUCCESS
;
2592 case IOCTL_STORAGE_PERSISTENT_RESERVE_IN
:
2593 case IOCTL_STORAGE_PERSISTENT_RESERVE_OUT
:
2595 status
= RequestValidatePersistentReserve(deviceExtension
, Request
, RequestParameters
, &dataLength
);
2601 case IOCTL_STORAGE_EJECT_MEDIA
:
2602 case IOCTL_STORAGE_LOAD_MEDIA
:
2603 case IOCTL_STORAGE_LOAD_MEDIA2
:
2605 status
= STATUS_SUCCESS
;
2608 break; // complete the irp
2611 case IOCTL_STORAGE_FIND_NEW_DEVICES
:
2614 IoInvalidateDeviceRelations(deviceExtension
->LowerPdo
, BusRelations
);
2616 status
= STATUS_SUCCESS
;
2619 break; // complete the irp
2622 case IOCTL_STORAGE_READ_CAPACITY
:
2624 if (RequestParameters
.Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(STORAGE_READ_CAPACITY
))
2626 dataLength
= sizeof(STORAGE_READ_CAPACITY
);
2627 status
= STATUS_BUFFER_TOO_SMALL
;
2629 else if (inZeroPowerState
!= FALSE
)
2631 status
= STATUS_NO_MEDIA_IN_DEVICE
;
2635 status
= STATUS_SUCCESS
;
2639 break; // complete the irp
2642 case IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT
:
2644 // for disk.sys only in original classpnp
2645 status
= STATUS_NOT_SUPPORTED
;
2648 break; // complete the irp
2651 #if (NTDDI_VERSION >= NTDDI_WIN8)
2652 case IOCTL_DISK_ARE_VOLUMES_READY
:
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
;
2664 case IOCTL_VOLUME_ONLINE
:
2665 case IOCTL_VOLUME_POST_ONLINE
:
2667 status
= STATUS_SUCCESS
;
2679 } //end of switch (ioctlCode)
2683 UCHAR currentStackLocationFlags
= 0;
2684 currentStackLocationFlags
= RequestGetCurrentStackLocationFlags(Request
);
2686 if ((status
== STATUS_VERIFY_REQUIRED
) &&
2687 (currentStackLocationFlags
& SL_OVERRIDE_VERIFY_VOLUME
))
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...
2694 processed
= RequestDispatchToSequentialQueue(Device
, Request
, RequestParameters
);
2698 if (NT_SUCCESS(status
))
2700 // Forward the request to serialized queue.
2701 status
= WdfDeviceEnqueueRequest(Device
, Request
);
2704 if (!NT_SUCCESS(status
))
2706 // Validation failed / forward failed, complete the request.
2707 RequestCompletion(deviceExtension
, Request
, status
, dataLength
);
2717 RequestDispatchSyncWithSequentialQueue(
2718 _In_ WDFDEVICE Device
,
2719 _In_ WDFREQUEST Request
,
2720 _In_ WDF_REQUEST_PARAMETERS RequestParameters
2723 Routine Description:
2725 These requests need to stay in caller's context and be processed in serialized manner.
2729 Device - handle to a WDF Device object
2731 Request - handle to the incoming WDF Request object
2733 RequestParameters - request parameters
2737 BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function).
2741 NTSTATUS status
= STATUS_SUCCESS
;
2742 BOOLEAN processed
= FALSE
;
2743 size_t dataLength
= 0;
2745 PCDROM_DEVICE_EXTENSION deviceExtension
= DeviceGetExtension(Device
);
2746 ULONG ioctlCode
= RequestParameters
.Parameters
.DeviceIoControl
.IoControlCode
;
2751 case IOCTL_CDROM_EXCLUSIVE_ACCESS
:
2754 status
= RequestValidateExclusiveAccess(Request
, RequestParameters
, &dataLength
);
2756 //2. keep the request in serialized manner and stay in user's context.
2757 if (NT_SUCCESS(status
))
2759 PCDROM_EXCLUSIVE_ACCESS exclusiveAccess
= NULL
;
2761 status
= WdfRequestRetrieveInputBuffer(Request
,
2762 RequestParameters
.Parameters
.DeviceIoControl
.InputBufferLength
,
2766 if (NT_SUCCESS(status
))
2768 // do not need to check "status" as it passed validation and cannot fail in WdfRequestRetrieveInputBuffer()
2769 switch (exclusiveAccess
->RequestType
)
2772 case ExclusiveAccessQueryState
:
2774 status
= RequestSetContextFields(Request
, RequestHandleExclusiveAccessQueryLockState
);
2778 case ExclusiveAccessLockDevice
:
2780 status
= RequestSetContextFields(Request
, RequestHandleExclusiveAccessLockDevice
);
2784 case ExclusiveAccessUnlockDevice
:
2786 status
= RequestSetContextFields(Request
, RequestHandleExclusiveAccessUnlockDevice
);
2791 // already valicated in RequestValidateExclusiveAccess()
2798 if (NT_SUCCESS(status
))
2800 // now, put the special synchronization information into the context
2801 status
= RequestSynchronizeProcessWithSerialQueue(Device
, Request
);
2803 // "status" is used for debugging in above statement, reset to success to avoid further work in this function.
2804 status
= STATUS_SUCCESS
;
2809 break; // complete the irp
2817 } //end of switch (ioctlCode)
2819 // Following process is only valid if the request is not really processed. (failed in validation)
2820 if (processed
&& !NT_SUCCESS(status
))
2822 UCHAR currentStackLocationFlags
= 0;
2823 currentStackLocationFlags
= RequestGetCurrentStackLocationFlags(Request
);
2825 if ((status
== STATUS_VERIFY_REQUIRED
) &&
2826 (currentStackLocationFlags
& SL_OVERRIDE_VERIFY_VOLUME
))
2829 // If the status is verified required and this request
2830 // should bypass verify required then retry the request.
2832 status
= STATUS_IO_DEVICE_ERROR
;
2833 UNREFERENCED_PARAMETER(status
); // disables prefast warning; defensive coding...
2835 processed
= RequestDispatchSyncWithSequentialQueue(Device
, Request
, RequestParameters
);
2839 // Validation failed / forward failed, complete the request.
2840 RequestCompletion(deviceExtension
, Request
, status
, dataLength
);
2849 RequestDispatchSpecialIoctls(
2850 _In_ WDFDEVICE Device
,
2851 _In_ WDFREQUEST Request
,
2852 _In_ WDF_REQUEST_PARAMETERS RequestParameters
2855 Routine Description:
2857 These requests need to be processed in different manner according to input parameters
2861 Device - handle to a WDF Device object
2863 Request - handle to the incoming WDF Request object
2865 RequestParameters - request parameters
2869 BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function).
2873 NTSTATUS status
= STATUS_SUCCESS
;
2874 BOOLEAN processed
= FALSE
;
2875 size_t dataLength
= 0;
2876 BOOLEAN requestCompleted
= FALSE
;
2878 PCDROM_DEVICE_EXTENSION deviceExtension
= DeviceGetExtension(Device
);
2879 PCDROM_DATA cdData
= &(deviceExtension
->DeviceAdditionalData
);
2880 ULONG ioctlCode
= RequestParameters
.Parameters
.DeviceIoControl
.IoControlCode
;
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
:
2889 // SPTI is considered special case as we need to set the MinorFunction before pass to low level.
2891 #if defined (_WIN64)
2892 if (WdfRequestIsFrom32BitProcess(Request
))
2894 if ((ioctlCode
== IOCTL_SCSI_PASS_THROUGH
) || (ioctlCode
== IOCTL_SCSI_PASS_THROUGH_DIRECT
))
2896 if (RequestParameters
.Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(SCSI_PASS_THROUGH32
))
2898 status
= STATUS_INVALID_PARAMETER
;
2903 if (RequestParameters
.Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(SCSI_PASS_THROUGH32_EX
))
2905 status
= STATUS_INVALID_PARAMETER
;
2912 if ((ioctlCode
== IOCTL_SCSI_PASS_THROUGH
) || (ioctlCode
== IOCTL_SCSI_PASS_THROUGH_DIRECT
))
2914 if (RequestParameters
.Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(SCSI_PASS_THROUGH
))
2916 status
= STATUS_INVALID_PARAMETER
;
2921 if (RequestParameters
.Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(SCSI_PASS_THROUGH_EX
))
2923 status
= STATUS_INVALID_PARAMETER
;
2928 if (!NT_SUCCESS(status
))
2930 // validation failed.
2931 RequestCompletion(deviceExtension
, Request
, status
, dataLength
);
2935 // keep the request in serialized manner and stay in user's context.
2936 status
= RequestSetContextFields(Request
, RequestHandleScsiPassThrough
);
2938 if (NT_SUCCESS(status
))
2940 status
= RequestSynchronizeProcessWithSerialQueue(Device
, Request
);
2944 RequestCompletion(deviceExtension
, Request
, status
, 0);
2948 requestCompleted
= TRUE
;
2953 case IOCTL_STORAGE_QUERY_PROPERTY
:
2955 if (RequestParameters
.Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(STORAGE_PROPERTY_QUERY
))
2957 status
= STATUS_INFO_LENGTH_MISMATCH
;
2961 PSTORAGE_PROPERTY_QUERY inputBuffer
= NULL
;
2963 status
= WdfRequestRetrieveInputBuffer(Request
,
2964 RequestParameters
.Parameters
.DeviceIoControl
.InputBufferLength
,
2968 if (NT_SUCCESS(status
))
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
2974 if (inputBuffer
->PropertyId
== StorageDeviceUniqueIdProperty
)
2976 // previously handled in classpnp
2977 // keep the request in serialized manner and stay in user's context.
2978 status
= RequestSetContextFields(Request
, RequestHandleQueryPropertyDeviceUniqueId
);
2980 if (NT_SUCCESS(status
))
2982 status
= RequestSynchronizeProcessWithSerialQueue(Device
, Request
);
2983 // remeber that the request has been completed.
2984 requestCompleted
= TRUE
;
2987 else if (inputBuffer
->PropertyId
== StorageDeviceWriteCacheProperty
)
2989 // previously handled in classpnp
2990 // keep the request in serialized manner and stay in user's context.
2991 status
= RequestSetContextFields(Request
, RequestHandleQueryPropertyWriteCache
);
2993 if (NT_SUCCESS(status
))
2995 status
= RequestSynchronizeProcessWithSerialQueue(Device
, Request
);
2996 // remeber that the request has been completed.
2997 requestCompleted
= TRUE
;
3002 // Pass to port driver for handling
3003 RequestDispatchUnknownRequests(Device
, Request
, RequestParameters
);
3005 // remeber that the request has been completed.
3006 requestCompleted
= TRUE
;
3011 // If cached data exists, return cached data. Otherwise, fail the request.
3012 if ((inputBuffer
->QueryType
== PropertyStandardQuery
) &&
3013 ((inputBuffer
->PropertyId
== StorageDeviceProperty
) || (inputBuffer
->PropertyId
== StorageAdapterProperty
)) )
3015 status
= RequestHandleQueryPropertyRetrieveCachedData(deviceExtension
, Request
, RequestParameters
, &dataLength
);
3019 status
= STATUS_ACCESS_DENIED
;
3029 // this IOCTL is a fake one, used for MCN process sync-ed with serial queue.
3030 case IOCTL_MCN_SYNC_FAKE_IOCTL
:
3032 PIRP irp
= WdfRequestWdmGetIrp(Request
);
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
))
3041 // This is the requset we use to sync Media Change Detection with sequential queue.
3042 status
= WdfDeviceEnqueueRequest(Device
, Request
);
3044 if (!NT_SUCCESS(status
))
3046 RequestCompletion(deviceExtension
, Request
, status
, dataLength
);
3049 requestCompleted
= TRUE
;
3054 // process as an unknown request.
3065 } //end of switch (ioctlCode)
3067 if (processed
&& !requestCompleted
)
3069 UCHAR currentStackLocationFlags
= 0;
3070 currentStackLocationFlags
= RequestGetCurrentStackLocationFlags(Request
);
3072 if ((status
== STATUS_VERIFY_REQUIRED
) &&
3073 (currentStackLocationFlags
& SL_OVERRIDE_VERIFY_VOLUME
))
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...
3080 processed
= RequestDispatchSpecialIoctls(Device
, Request
, RequestParameters
);
3084 RequestCompletion(deviceExtension
, Request
, status
, dataLength
);
3093 RequestDispatchUnknownRequests(
3094 _In_ WDFDEVICE Device
,
3095 _In_ WDFREQUEST Request
,
3096 _In_ WDF_REQUEST_PARAMETERS RequestParameters
3099 Routine Description:
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.
3107 Device - handle to a WDF Device object
3109 Request - handle to the incoming WDF Request object
3111 RequestParameters - request parameters
3115 BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function).
3119 NTSTATUS status
= STATUS_UNSUCCESSFUL
;
3120 PCDROM_DEVICE_EXTENSION deviceExtension
= DeviceGetExtension(Device
);
3122 ULONG baseCode
= DEVICE_TYPE_FROM_CTL_CODE(RequestParameters
.Parameters
.DeviceIoControl
.IoControlCode
);
3124 if ((KeGetCurrentIrql() != PASSIVE_LEVEL
) ||
3125 (baseCode
== FILE_DEVICE_ACPI
))
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
);
3134 // keep the request in serialized manner and stay in user's context.
3135 status
= RequestSetContextFields(Request
, RequestHandleUnknownIoctl
);
3137 if (NT_SUCCESS(status
))
3139 status
= RequestSynchronizeProcessWithSerialQueue(Device
, Request
);
3143 RequestCompletion(deviceExtension
, Request
, status
, 0);
3147 UNREFERENCED_PARAMETER(status
); //defensive coding, avoid PREFAST warning.
3149 // All unknown IOCTLs are processed in this function.
3150 return TRUE
; //processed
3154 RequestProcessInternalDeviceControl(
3155 _In_ WDFREQUEST Request
,
3156 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
3159 Routine Description:
3161 all internal IOCTL will be send to lower driver asynchronously.
3165 Request - handle to the incoming WDF Request object
3166 DeviceExtension - device extension structure
3174 NTSTATUS status
= STATUS_SUCCESS
;
3176 PIO_STACK_LOCATION irpStack
= NULL
;
3177 PIO_STACK_LOCATION nextStack
= NULL
;
3178 BOOLEAN requestSent
= FALSE
;
3180 irp
= WdfRequestWdmGetIrp(Request
);
3181 irpStack
= IoGetCurrentIrpStackLocation(irp
);
3182 nextStack
= IoGetNextIrpStackLocation(irp
);
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
;
3189 WdfRequestSetCompletionRoutine(Request
, RequestDummyCompletionRoutine
, NULL
);
3191 status
= RequestSend(DeviceExtension
,
3193 DeviceExtension
->IoTarget
,
3197 // send the request straight down (asynchronously)
3201 RequestCompletion(DeviceExtension
, Request
, status
, WdfRequestGetInformation(Request
));
3210 // Serial I/O Queue Event callbacks
3214 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
3215 SequentialQueueEvtIoReadWrite(
3216 _In_ WDFQUEUE Queue
,
3217 _In_ WDFREQUEST Request
,
3221 Routine Description:
3223 validate and process read/write request.
3227 Queue - parallel queue itself
3229 Request - handle to the incoming WDF Request object
3231 Length - read / write lenght
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
);
3247 // Get the request parameters
3248 WDF_REQUEST_PARAMETERS_INIT(&requestParameters
);
3249 WdfRequestGetParameters(Request
, &requestParameters
);
3251 if (requestParameters
.Type
== WdfRequestTypeRead
)
3253 TracePrint((TRACE_LEVEL_VERBOSE
, TRACE_FLAG_GENERAL
,
3254 "Receiving READ, Length %Ix\n", (ULONG
) Length
));
3258 TracePrint((TRACE_LEVEL_VERBOSE
, TRACE_FLAG_GENERAL
,
3259 "Receiving WRITE, Length %Ix\n", (ULONG
) Length
));
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
))
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);
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
;
3280 // Fail READ/WRITE requests when music is playing
3281 if (deviceExtension
->DeviceAdditionalData
.PlayActive
)
3283 RequestCompletion(deviceExtension
, Request
, STATUS_DEVICE_BUSY
, 0);
3288 // Fail READ/WRITE requests from non-owners if the drive is locked
3289 if (EXCLUSIVE_MODE(cdData
) && !EXCLUSIVE_OWNER(cdData
, WdfRequestGetFileObject(Request
)))
3291 RequestCompletion(deviceExtension
, Request
, STATUS_ACCESS_DENIED
, 0);
3296 // Succeed READ/WRITE requests of length 0
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
);
3306 // If there is an unexpected write request, we want to rediscover MMC capabilities
3307 if (!deviceExtension
->DeviceAdditionalData
.Mmc
.WriteAllowed
&&
3308 (requestParameters
.Type
== WdfRequestTypeWrite
))
3310 // Schedule MMC capabilities update now, but perform it later in a work item
3311 deviceExtension
->DeviceAdditionalData
.Mmc
.UpdateState
= CdromMmcUpdateRequired
;
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
))
3318 deviceExtension
->ReadWriteWorkItemContext
.OriginalRequest
= Request
;
3319 WdfWorkItemEnqueue(deviceExtension
->ReadWriteWorkItem
);
3321 status
= STATUS_SUCCESS
;
3325 status
= RequestValidateReadWrite(deviceExtension
, Request
, requestParameters
);
3327 if (NT_SUCCESS(status
))
3329 status
= RequestHandleReadWrite(deviceExtension
, Request
, requestParameters
);
3333 if (!NT_SUCCESS(status
))
3335 RequestCompletion(deviceExtension
, Request
, status
, 0);
3344 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
3345 ReadWriteWorkItemRoutine(
3346 _In_ WDFWORKITEM WorkItem
3350 Routine Description:
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.
3358 WorkItem - WDF work item
3366 PCDROM_DEVICE_EXTENSION deviceExtension
= NULL
;
3367 WDFREQUEST readWriteRequest
= NULL
;
3368 WDF_REQUEST_PARAMETERS readWriteRequestParameters
;
3369 NTSTATUS status
= STATUS_SUCCESS
;
3373 deviceExtension
= WdfObjectGetTypedContext(WdfWorkItemGetParentObject(WorkItem
), CDROM_DEVICE_EXTENSION
);
3374 readWriteRequest
= deviceExtension
->ReadWriteWorkItemContext
.OriginalRequest
;
3375 deviceExtension
->ReadWriteWorkItemContext
.OriginalRequest
= NULL
;
3377 WDF_REQUEST_PARAMETERS_INIT(&readWriteRequestParameters
);
3378 WdfRequestGetParameters(readWriteRequest
, &readWriteRequestParameters
);
3380 if (DeviceIsMmcUpdateRequired(deviceExtension
->Device
))
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
);
3388 // Now verify and process the request
3389 if (NT_SUCCESS(status
))
3391 status
= RequestValidateReadWrite(deviceExtension
, readWriteRequest
, readWriteRequestParameters
);
3393 if (NT_SUCCESS(status
))
3395 status
= RequestHandleReadWrite(deviceExtension
, readWriteRequest
, readWriteRequestParameters
);
3398 // Complete the request immediately on failure
3399 if (!NT_SUCCESS(status
))
3401 RequestCompletion(deviceExtension
, readWriteRequest
, status
, 0);
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
3416 Routine Description:
3418 validate and process IOCTL request.
3422 Queue - sequential queue
3424 Request - handle to the incoming WDF Request object
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
;
3439 UNREFERENCED_PARAMETER(OutputBufferLength
);
3440 UNREFERENCED_PARAMETER(InputBufferLength
);
3441 UNREFERENCED_PARAMETER(IoControlCode
);
3443 // get the request parameters
3444 WDF_REQUEST_PARAMETERS_INIT(&requestParameters
);
3445 WdfRequestGetParameters(Request
, &requestParameters
);
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
)))
3451 BOOLEAN isBlocked
= FALSE
;
3453 status
= RequestIsIoctlBlockedByExclusiveAccess(Request
, &isBlocked
);
3454 if (NT_SUCCESS(status
) && isBlocked
)
3456 if (requestContext
->SyncRequired
)
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
);
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);
3474 if (!cdData
->Mmc
.WriteAllowed
&&
3475 ((requestParameters
.Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_IS_WRITABLE
) ||
3476 (requestParameters
.Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_DISK_VERIFY
)))
3478 cdData
->Mmc
.UpdateState
= CdromMmcUpdateRequired
;
3481 // check if this is a synchronized ioctl
3482 if (requestContext
->SyncRequired
)
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
);
3490 deviceExtension
->IoctlWorkItemContext
.OriginalRequest
= Request
;
3492 // all other IOCTL processing is currently processed via a
3493 // work item running at PASSIVE_LEVEL.
3494 WdfWorkItemEnqueue(deviceExtension
->IoctlWorkItem
);
3502 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
3503 IoctlWorkItemRoutine(
3504 _In_ WDFWORKITEM WorkItem
3508 Routine Description:
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.
3516 WorkItem - WDF work item
3524 PCDROM_DEVICE_EXTENSION deviceExtension
= NULL
;
3528 deviceExtension
= WdfObjectGetTypedContext(WdfWorkItemGetParentObject(WorkItem
), CDROM_DEVICE_EXTENSION
);
3530 if (DeviceIsMmcUpdateRequired(deviceExtension
->Device
))
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
);
3538 RequestProcessSerializedIoctl(deviceExtension
, deviceExtension
->IoctlWorkItemContext
.OriginalRequest
);
3542 _IRQL_requires_max_(PASSIVE_LEVEL
)
3544 RequestProcessSerializedIoctl(
3545 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension
,
3546 _In_ WDFREQUEST Request
3549 Routine Description:
3551 a dispatch routine for all functions to process IOCTLs.
3555 DeviceExtension - device context
3557 Request - handle to the incoming WDF Request object
3565 NTSTATUS status
= STATUS_SUCCESS
;
3566 size_t information
= 0;
3567 WDF_REQUEST_PARAMETERS requestParameters
;
3568 BOOLEAN completeRequest
= TRUE
;
3572 // Get the Request parameters
3573 WDF_REQUEST_PARAMETERS_INIT(&requestParameters
);
3574 WdfRequestGetParameters(Request
, &requestParameters
);
3576 NormalizeIoctl(&requestParameters
);
3579 switch (requestParameters
.Parameters
.DeviceIoControl
.IoControlCode
)
3581 case IOCTL_CDROM_READ_TOC
:
3582 case IOCTL_CDROM_GET_LAST_SESSION
:
3583 status
= RequestHandleReadTOC(DeviceExtension
, Request
, requestParameters
, &information
);
3586 case IOCTL_CDROM_READ_TOC_EX
:
3587 status
= RequestHandleReadTocEx(DeviceExtension
, Request
, requestParameters
, &information
);
3590 case IOCTL_CDROM_GET_CONFIGURATION
:
3591 status
= RequestHandleGetConfiguration(DeviceExtension
, Request
, requestParameters
, &information
);
3594 case IOCTL_CDROM_RAW_READ
:
3595 status
= DeviceHandleRawRead(DeviceExtension
, Request
, requestParameters
, &information
);
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
);
3607 case IOCTL_DISK_VERIFY
:
3608 status
= RequestHandleDiskVerify(DeviceExtension
, Request
, requestParameters
, &information
);
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
);
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
);
3628 case IOCTL_DISK_IS_WRITABLE
:
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
3635 if (DeviceExtension
->DeviceAdditionalData
.Mmc
.WriteAllowed
&&
3636 (DeviceExtension
->DeviceAdditionalData
.Mmc
.ValidationSchema
== FeatureDefectManagement
))
3638 status
= STATUS_SUCCESS
;
3642 status
= STATUS_MEDIA_WRITE_PROTECTED
;
3647 case IOCTL_CDROM_PLAY_AUDIO_MSF
:
3648 status
= DeviceHandlePlayAudioMsf(DeviceExtension
, Request
, requestParameters
, &information
);
3651 case IOCTL_CDROM_READ_Q_CHANNEL
:
3652 status
= DeviceHandleReadQChannel(DeviceExtension
, Request
, requestParameters
, &information
);
3655 case IOCTL_CDROM_PAUSE_AUDIO
:
3656 status
= DeviceHandlePauseAudio(DeviceExtension
, Request
, &information
);
3659 case IOCTL_CDROM_RESUME_AUDIO
:
3660 status
= DeviceHandleResumeAudio(DeviceExtension
, Request
, &information
);
3663 case IOCTL_CDROM_SEEK_AUDIO_MSF
:
3664 status
= DeviceHandleSeekAudioMsf(DeviceExtension
, Request
, requestParameters
, &information
);
3667 case IOCTL_CDROM_STOP_AUDIO
:
3668 status
= DeviceHandleStopAudio(DeviceExtension
, Request
, &information
);
3671 case IOCTL_CDROM_GET_VOLUME
:
3672 case IOCTL_CDROM_SET_VOLUME
:
3673 status
= DeviceHandleGetSetVolume(DeviceExtension
, Request
, requestParameters
, &information
);
3676 case IOCTL_DVD_GET_REGION
:
3677 status
= RequestHandleGetDvdRegion(DeviceExtension
, Request
, &information
);
3680 case IOCTL_DVD_READ_STRUCTURE
:
3681 status
= DeviceHandleReadDvdStructure(DeviceExtension
, Request
, requestParameters
, &information
);
3684 case IOCTL_DVD_END_SESSION
:
3685 status
= DeviceHandleDvdEndSession(DeviceExtension
, Request
, requestParameters
, &information
);
3688 case IOCTL_DVD_START_SESSION
:
3689 case IOCTL_DVD_READ_KEY
:
3690 status
= DeviceHandleDvdStartSessionReadKey(DeviceExtension
, Request
, requestParameters
, &information
);
3693 case IOCTL_DVD_SEND_KEY
:
3694 case IOCTL_DVD_SEND_KEY2
:
3695 status
= DeviceHandleDvdSendKey(DeviceExtension
, Request
, requestParameters
, &information
);
3698 case IOCTL_STORAGE_SET_READ_AHEAD
:
3699 status
= DeviceHandleSetReadAhead(DeviceExtension
, Request
, requestParameters
, &information
);
3702 case IOCTL_CDROM_SET_SPEED
:
3703 status
= DeviceHandleSetSpeed(DeviceExtension
, Request
, requestParameters
, &information
);
3706 case IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE
:
3707 case IOCTL_AACS_READ_MEDIA_KEY_BLOCK
:
3708 status
= DeviceHandleAacsReadMediaKeyBlock(DeviceExtension
, Request
, requestParameters
, &information
);
3711 case IOCTL_AACS_START_SESSION
:
3712 status
= DeviceHandleAacsStartSession(DeviceExtension
, Request
, requestParameters
, &information
);
3715 case IOCTL_AACS_END_SESSION
:
3716 status
= DeviceHandleAacsEndSession(DeviceExtension
, Request
, requestParameters
, &information
);
3719 case IOCTL_AACS_SEND_CERTIFICATE
:
3720 status
= DeviceHandleAacsSendCertificate(DeviceExtension
, Request
, requestParameters
, &information
);
3723 case IOCTL_AACS_GET_CERTIFICATE
:
3724 status
= DeviceHandleAacsGetCertificate(DeviceExtension
, Request
, requestParameters
, &information
);
3727 case IOCTL_AACS_GET_CHALLENGE_KEY
:
3728 status
= DeviceHandleAacsGetChallengeKey(DeviceExtension
, Request
, requestParameters
, &information
);
3731 case IOCTL_AACS_SEND_CHALLENGE_KEY
:
3732 status
= DeviceHandleSendChallengeKey(DeviceExtension
, Request
, requestParameters
, &information
);
3735 case IOCTL_AACS_READ_VOLUME_ID
:
3736 status
= DeviceHandleReadVolumeId(DeviceExtension
, Request
, requestParameters
, &information
);
3739 case IOCTL_AACS_READ_SERIAL_NUMBER
:
3740 status
= DeviceHandleAacsReadSerialNumber(DeviceExtension
, Request
, requestParameters
, &information
);
3743 case IOCTL_AACS_READ_MEDIA_ID
:
3744 status
= DeviceHandleAacsReadMediaId(DeviceExtension
, Request
, requestParameters
, &information
);
3747 case IOCTL_AACS_READ_BINDING_NONCE
:
3748 status
= DeviceHandleAacsReadBindingNonce(DeviceExtension
, Request
, requestParameters
, &information
);
3751 case IOCTL_AACS_GENERATE_BINDING_NONCE
:
3752 status
= DeviceHandleAacsGenerateBindingNonce(DeviceExtension
, Request
, requestParameters
, &information
);
3755 case IOCTL_CDROM_ENABLE_STREAMING
:
3756 status
= RequestHandleEnableStreaming(DeviceExtension
, Request
, &information
);
3759 case IOCTL_CDROM_SEND_OPC_INFORMATION
:
3760 status
= RequestHandleSendOpcInformation(DeviceExtension
, Request
, &information
);
3763 case IOCTL_CDROM_GET_PERFORMANCE
:
3764 status
= RequestHandleGetPerformance(DeviceExtension
, Request
, requestParameters
, &information
);
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
);
3772 case IOCTL_STORAGE_MEDIA_REMOVAL
:
3773 case IOCTL_STORAGE_EJECTION_CONTROL
:
3775 status
= RequestHandleEjectionControl(DeviceExtension
, Request
, requestParameters
, &information
);
3780 case IOCTL_STORAGE_EJECT_MEDIA
:
3781 case IOCTL_STORAGE_LOAD_MEDIA
:
3782 case IOCTL_STORAGE_LOAD_MEDIA2
:
3784 status
= RequestHandleLoadEjectMedia(DeviceExtension
, Request
, requestParameters
, &information
);
3789 case IOCTL_STORAGE_MCN_CONTROL
:
3791 status
= RequestHandleMcnControl(DeviceExtension
, Request
, &information
);
3796 case IOCTL_STORAGE_RESERVE
:
3797 case IOCTL_STORAGE_RELEASE
:
3799 status
= RequestHandleReserveRelease(DeviceExtension
, Request
, requestParameters
, &information
);
3804 case IOCTL_STORAGE_PERSISTENT_RESERVE_IN
:
3805 case IOCTL_STORAGE_PERSISTENT_RESERVE_OUT
:
3807 status
= RequestHandlePersistentReserve(DeviceExtension
, Request
, requestParameters
, &information
);
3812 #if (NTDDI_VERSION >= NTDDI_WIN8)
3813 case IOCTL_DISK_ARE_VOLUMES_READY
:
3815 status
= RequestHandleAreVolumesReady(DeviceExtension
, Request
, requestParameters
, &information
);
3817 completeRequest
= FALSE
;
3822 case IOCTL_VOLUME_ONLINE
:
3823 case IOCTL_VOLUME_POST_ONLINE
:
3825 status
= RequestHandleVolumeOnline(DeviceExtension
, Request
, requestParameters
, &information
);
3833 status
= STATUS_ACCESS_DENIED
;
3836 } // end of switch(ioctl)
3838 if (completeRequest
)
3840 RequestCompletion(DeviceExtension
, Request
, status
, information
);
3847 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
3848 SequentialQueueEvtCanceledOnQueue(
3849 _In_ WDFQUEUE Queue
,
3850 _In_ WDFREQUEST Request
3853 Routine Description:
3855 Perform cancellation when request is still in queue.
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.
3862 Queue - serial queue
3863 Request - handle to the incoming WDF Request object
3871 PCDROM_REQUEST_CONTEXT requestContext
= RequestGetContext(Request
);
3873 if (requestContext
->SyncRequired
)
3875 KeSetEvent(requestContext
->SyncEvent
, IO_CD_ROM_INCREMENT
, FALSE
);
3879 PCDROM_DEVICE_EXTENSION deviceExtension
= NULL
;
3880 WDFDEVICE device
= WdfIoQueueGetDevice(Queue
);
3882 deviceExtension
= DeviceGetExtension(device
);
3884 RequestCompletion(deviceExtension
, Request
, STATUS_CANCELLED
, 0);
3893 RequestSynchronizeProcessWithSerialQueue(
3894 _In_ WDFDEVICE Device
,
3895 _In_ WDFREQUEST Request
3898 Routine Description:
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.
3907 DeviceExtension - device context
3909 Request - handle to the incoming WDF Request object
3917 NTSTATUS status
= STATUS_SUCCESS
;
3918 PCDROM_DEVICE_EXTENSION deviceExtension
= DeviceGetExtension(Device
);
3919 PCDROM_REQUEST_CONTEXT requestContext
= RequestGetContext(Request
);
3920 PKEVENT bufferToFree
= requestContext
->SyncEvent
;
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"));
3927 RequestCompletion(deviceExtension
, Request
, STATUS_INVALID_LEVEL
, 0);
3928 return STATUS_INVALID_LEVEL
;
3931 // init the synchronization event
3932 KeInitializeEvent(requestContext
->SyncEvent
, NotificationEvent
, FALSE
);
3934 // do we still need to do something like this?
3935 // SET_FLAG(nextStack->Flags, SL_OVERRIDE_VERIFY_VOLUME);
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
);
3946 if (!NT_SUCCESS(status
))
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
));
3955 NTSTATUS waitStatus
= STATUS_UNSUCCESSFUL
;
3956 PCDROM_DATA cdData
= &(deviceExtension
->DeviceAdditionalData
);
3957 BOOLEAN fCallSyncCallback
= FALSE
;
3958 PIRP irp
= WdfRequestWdmGetIrp(Request
);
3960 // ok, now wait on the event
3961 while (waitStatus
!= STATUS_SUCCESS
)
3963 waitStatus
= KeWaitForSingleObject(requestContext
->SyncEvent
, Executive
, KernelMode
, TRUE
, NULL
);
3964 if (waitStatus
== STATUS_SUCCESS
) // must check equality -- STATUS_ALERTED is success code
3968 else if (waitStatus
!= STATUS_ALERTED
)
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
));
3976 else if (PsIsThreadTerminating(PsGetCurrentThread()))
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
))
3983 // cancellation routine was called
3984 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_IOCTL
,
3985 "Sychronize Ioctl: request %p cancelled from device %p\n",
3990 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_IOCTL
,
3991 "Sychronize Ioctl: request %p could not be cancelled from device %p\n",
3997 TracePrint((TRACE_LEVEL_WARNING
, TRACE_FLAG_IOCTL
,
3998 "SPURIOUS ALERT waiting for Request %p on device %p (%!STATUS!)\n",
3999 Request
, Device
, status
));
4001 } // end of wait loop on the event
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
))
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);
4012 else if (EXCLUSIVE_MODE(cdData
) && !EXCLUSIVE_OWNER(cdData
, WdfRequestGetFileObject(Request
)))
4014 WDF_REQUEST_PARAMETERS requestParameters
;
4015 BOOLEAN isBlocked
= FALSE
;
4017 // get the request parameters
4018 WDF_REQUEST_PARAMETERS_INIT(&requestParameters
);
4019 WdfRequestGetParameters(Request
, &requestParameters
);
4021 status
= RequestIsIoctlBlockedByExclusiveAccess(Request
, &isBlocked
);
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);
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
;
4039 fCallSyncCallback
= TRUE
;
4042 if (fCallSyncCallback
)
4044 // Synchronization completed successfully. Call the requested routine
4045 status
= requestContext
->SyncCallback(Device
, Request
);
4049 // The next SequentialQueue evt routine will not be triggered until the current request is completed.
4051 // clean up the request context setting.
4052 FREE_POOL(bufferToFree
);
4058 RequestIsIoctlBlockedByExclusiveAccess(
4059 _In_ WDFREQUEST Request
,
4060 _Out_ PBOOLEAN IsBlocked
4063 Routine Description:
4065 Check if the IOCTL request should be blocked or not according to
4066 the exclusive lock stat.
4070 Request - handle to the incoming WDF Request object
4076 IsBlocked - TRUE (be blocked); FALSE (not blocked)
4080 NTSTATUS status
= STATUS_SUCCESS
;
4081 ULONG ioctlCode
= 0;
4083 WDF_REQUEST_PARAMETERS requestParameters
;
4085 // Get the Request parameters
4086 WDF_REQUEST_PARAMETERS_INIT(&requestParameters
);
4087 WdfRequestGetParameters(Request
, &requestParameters
);
4089 // check and initialize parameter
4090 if (IsBlocked
== NULL
)
4092 //This is an internal function and this parameter must be supplied.
4095 return STATUS_INVALID_PARAMETER
;
4102 // check if this is an IOCTL
4103 if ((requestParameters
.Type
== WdfRequestTypeDeviceControl
) ||
4104 (requestParameters
.Type
== WdfRequestTypeDeviceControlInternal
))
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).
4113 ioctlCode
= requestParameters
.Parameters
.DeviceIoControl
.IoControlCode
;
4114 baseCode
= DEVICE_TYPE_FROM_CTL_CODE(ioctlCode
);
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
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
)
4134 PSTORAGE_PROPERTY_QUERY query
= NULL
;
4135 status
= WdfRequestRetrieveInputBuffer(Request
,
4136 requestParameters
.Parameters
.DeviceIoControl
.InputBufferLength
,
4140 if (NT_SUCCESS(status
))
4144 if (query
->QueryType
== PropertyExistsQuery
)
4148 else if ((query
->QueryType
== PropertyStandardQuery
) &&
4149 ((query
->PropertyId
== StorageDeviceProperty
) ||
4150 (query
->PropertyId
== StorageAdapterProperty
)))
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
)
4170 // this should only be called with an IOCTL
4173 status
= STATUS_INVALID_PARAMETER
;
4180 DeviceIsMmcUpdateRequired(
4181 _In_ WDFDEVICE Device
4184 Routine Description:
4186 Check if the device needs to update its MMC information.
4190 Device - device to be checked.
4194 TRUE (require update); FALSE (not require update)
4198 PCDROM_DEVICE_EXTENSION deviceExtension
= DeviceGetExtension(Device
);
4199 PCDROM_DATA cdData
= &(deviceExtension
->DeviceAdditionalData
);
4201 if ((cdData
->Mmc
.IsMmc
) &&
4202 (cdData
->Mmc
.UpdateState
== CdromMmcUpdateRequired
))
4208 // no update required: just proceed
4214 NTAPI
/* ReactOS Change: GCC Does not support STDCALL by default */
4216 _In_ WDFOBJECT Request
4219 Routine Description:
4221 Request cleanup callback.
4225 Request - request to clean up.
4233 WDFREQUEST request
= (WDFREQUEST
)Request
;
4234 PCDROM_REQUEST_CONTEXT requestContext
= RequestGetContext(request
);
4236 if (requestContext
->SyncRequired
)
4238 // the event should have been signaled, just check that
4239 NT_ASSERT(KeReadStateEvent(requestContext
->SyncEvent
) != 0);