diff options
Diffstat (limited to 'storage/class/cdrom/src/cdrom.c')
| -rw-r--r-- | storage/class/cdrom/src/cdrom.c | 4225 |
1 files changed, 0 insertions, 4225 deletions
diff --git a/storage/class/cdrom/src/cdrom.c b/storage/class/cdrom/src/cdrom.c deleted file mode 100644 index fccf4a0e..00000000 --- a/storage/class/cdrom/src/cdrom.c +++ /dev/null @@ -1,4225 +0,0 @@ -/*-- - -Copyright (C) Microsoft Corporation. All rights reserved. - -Module Name: - - cdrom.c - -Abstract: - - The CDROM class driver tranlates IRPs to SRBs with embedded CDBs - and sends them to its devices through the port driver. - -Environment: - - kernel mode only - -Notes: - - -Revision History: - ---*/ - -// this definition is used to link _StorDebugPrint() function. -#define DEBUG_MAIN_SOURCE 1 - - -#include "ntddk.h" -#include "ntstrsafe.h" - -#include "ntddstor.h" -#include "ntddtape.h" -#include "wdfcore.h" -#include "devpkey.h" - -#include "cdrom.h" -#include "ioctl.h" -#include "mmc.h" -#include "scratch.h" - - -#ifdef DEBUG_USE_WPP -#include "cdrom.tmh" -#endif - -BOOLEAN -BootEnvironmentIsWinPE( - VOID - ); - -#ifdef ALLOC_PRAGMA - -#pragma alloc_text(INIT, DriverEntry) -#pragma alloc_text(INIT, BootEnvironmentIsWinPE) - -#pragma alloc_text(PAGE, DriverEvtCleanup) -#pragma alloc_text(PAGE, DriverEvtDeviceAdd) -#pragma alloc_text(PAGE, DeviceEvtCleanup) -#pragma alloc_text(PAGE, DeviceEvtSelfManagedIoCleanup) -#pragma alloc_text(PAGE, DeviceEvtD0Exit) -#pragma alloc_text(PAGE, CreateQueueEvtIoDefault) -#pragma alloc_text(PAGE, DeviceEvtFileClose) -#pragma alloc_text(PAGE, DeviceCleanupProtectedLocks) -#pragma alloc_text(PAGE, DeviceCleanupDisableMcn) -#pragma alloc_text(PAGE, RequestProcessSerializedIoctl) -#pragma alloc_text(PAGE, ReadWriteWorkItemRoutine) -#pragma alloc_text(PAGE, IoctlWorkItemRoutine) -#pragma alloc_text(PAGE, DeviceEvtSurpriseRemoval) - -#endif - -NTSTATUS -DriverEntry( - _In_ PDRIVER_OBJECT DriverObject, - _In_ PUNICODE_STRING RegistryPath - ) -/*++ - -Routine Description: - - Installable driver initialization entry point. - This entry point is called directly by the I/O system. - -Arguments: - - DriverObject - pointer to the driver object - - RegistryPath - pointer to a unicode string representing the path, - to driver-specific key in the registry. - -Return Value: - - STATUS_SUCCESS if successful, - STATUS_UNSUCCESSFUL otherwise. - ---*/ -{ - NTSTATUS status; - WDF_DRIVER_CONFIG config; - WDF_OBJECT_ATTRIBUTES attributes; - WDFDRIVER driverObject = NULL; - - PAGED_CODE(); - - // Initialize WPP Tracing - WPP_INIT_TRACING(DriverObject, RegistryPath); - - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, - "CDROM.SYS DriverObject %p loading\n", - DriverObject)); - - // Register DeviceAdd and DriverEvtCleanup callback. - // WPP_CLEANUP will be called in DriverEvtCleanup - WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CDROM_DRIVER_EXTENSION); - attributes.EvtCleanupCallback = DriverEvtCleanup; - - WDF_DRIVER_CONFIG_INIT(&config, DriverEvtDeviceAdd); - - status = WdfDriverCreate(DriverObject, - RegistryPath, - &attributes, - &config, - &driverObject); - - if (!NT_SUCCESS(status)) - { - TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT, - "WdfDriverCreate failed. %x\n", - status)); - - // Cleanup tracing here because DriverUnload will not be called - // as we have failed to create WDFDRIVER object itself. - WPP_CLEANUP(DriverObject); - - } - else - { - PCDROM_DRIVER_EXTENSION driverExtension = DriverGetExtension(driverObject); - - // Copy the registry path into the driver extension so we can use it later - driverExtension->Version = 0x01; - driverExtension->DriverObject = DriverObject; - - if (BootEnvironmentIsWinPE()) { - - SET_FLAG(driverExtension->Flags, CDROM_FLAG_WINPE_MODE); - } - - } - - return status; -} - - -BOOLEAN -BootEnvironmentIsWinPE( - VOID - ) -/*++ - -Routine Description: - - This routine determines if the boot enviroment is WinPE - -Arguments: - - None - -Return Value: - - BOOLEAN - TRUE if the environment is WinPE; FALSE otherwise - ---*/ -{ - NTSTATUS status; - WDFKEY registryKey = NULL; - - DECLARE_CONST_UNICODE_STRING(registryKeyName, WINPE_REG_KEY_NAME); - - PAGED_CODE(); - - status = WdfRegistryOpenKey(NULL, - ®istryKeyName, - KEY_READ, - WDF_NO_OBJECT_ATTRIBUTES, - ®istryKey); - - if (!NT_SUCCESS(status)) - { - return FALSE; - } - - WdfRegistryClose(registryKey); - return TRUE; -} // end BootEnvironmentIsWinPE() - - -VOID -DriverEvtCleanup( - _In_ WDFOBJECT Driver - ) -/*++ -Routine Description: - - Free all the resources allocated in DriverEntry. - -Arguments: - - Driver - handle to a WDF Driver object. - -Return Value: - - VOID. - ---*/ -{ - WDFDRIVER driver = (WDFDRIVER)Driver; - - PAGED_CODE (); - - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, - "CDROM.SYS DriverObject %p cleanup. Will be unloaded soon\n", - driver)); - - // Stop WPP Tracing - WPP_CLEANUP( WdfDriverWdmGetDriverObject(driver) ); - - - return; -} - - -NTSTATUS -DriverEvtDeviceAdd( - _In_ WDFDRIVER Driver, - _Inout_ PWDFDEVICE_INIT DeviceInit - ) -/*++ - -Routine Description: - - EvtDeviceAdd is called by the framework in response to AddDevice - call from the PnP manager. - - -Arguments: - - Driver - Handle to a framework driver object created in DriverEntry - - DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. - -Return Value: - - NTSTATUS - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - PCDROM_DRIVER_EXTENSION driverExtension = NULL; - WDFDEVICE device = NULL; - PCDROM_DEVICE_EXTENSION deviceExtension = NULL; - BOOLEAN deviceClaimed = FALSE; - - WDF_OBJECT_ATTRIBUTES attributes; - WDF_FILEOBJECT_CONFIG fileObjectConfig; - WDF_IO_TARGET_OPEN_PARAMS ioTargetOpenParams; - WDF_IO_QUEUE_CONFIG queueConfig; - WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; - WDF_REMOVE_LOCK_OPTIONS removeLockOptions; - PWCHAR wideDeviceName = NULL; - UNICODE_STRING unicodeDeviceName; - PDEVICE_OBJECT lowerPdo = NULL; - ULONG deviceNumber = 0; - ULONG devicePropertySessionId = INVALID_SESSION; - ULONG devicePropertySize = 0; - DEVPROPTYPE devicePropertyType = DEVPROP_TYPE_EMPTY; - - PAGED_CODE(); - - driverExtension = DriverGetExtension(Driver); - - // 0. Initialize the objects that we're going to use - RtlInitUnicodeString(&unicodeDeviceName, NULL); - - // 1. Register PnP&Power callbacks for any we are interested in. - // If a callback isn't set, Framework will take the default action by itself. - { - // Zero out the PnpPowerCallbacks structure. - WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); - - // Use this callback to init resources that are used by the device and only needs to be called once. - pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = DeviceEvtSelfManagedIoInit; - - // Use this callback to prepare device for coming back from a lower power mode to D0. - pnpPowerCallbacks.EvtDeviceD0Entry = DeviceEvtD0Entry; - - // Use this callback to prepare device for entering into a lower power mode. - pnpPowerCallbacks.EvtDeviceD0Exit = DeviceEvtD0Exit; - - // Use this callback to free any resources used by device and will be called when the device is - // powered down. - pnpPowerCallbacks.EvtDeviceSelfManagedIoCleanup = DeviceEvtSelfManagedIoCleanup; - - pnpPowerCallbacks.EvtDeviceSurpriseRemoval = DeviceEvtSurpriseRemoval; - - // Register the PnP and power callbacks. - WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); - } - - // 2. Register the EvtIoInCallerContext to deal with IOCTLs that need to stay in original context. - WdfDeviceInitSetIoInCallerContextCallback(DeviceInit, - DeviceEvtIoInCallerContext); - - // 3. Register PreprocessCallback for IRP_MJ_POWER, IRP_MJ_FLUSH_BUFFERS and IRP_MJ_SHUTDOWN - { - UCHAR minorFunctions[1]; - - minorFunctions[0] = IRP_MN_SET_POWER; - - status = WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit, - RequestProcessSetPower, - IRP_MJ_POWER, - minorFunctions, - RTL_NUMBER_OF(minorFunctions)); - if (!NT_SUCCESS(status)) - { - TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, - "DriverEvtDeviceAdd: Assign IrpPreprocessCallback for IRP_MJ_POWER failed, " - "status: 0x%X\n", status)); - - goto Exit; - } - - status = WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit, - RequestProcessShutdownFlush, - IRP_MJ_FLUSH_BUFFERS, - NULL, - 0); - if (!NT_SUCCESS(status)) - { - TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, - "DriverEvtDeviceAdd: Assign IrpPreprocessCallback for IRP_MJ_FLUSH_BUFFERS failed, " - "status: 0x%X\n", status)); - - goto Exit; - } - - status = WdfDeviceInitAssignWdmIrpPreprocessCallback(DeviceInit, - RequestProcessShutdownFlush, - IRP_MJ_SHUTDOWN, - NULL, - 0); - if (!NT_SUCCESS(status)) - { - TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, - "DriverEvtDeviceAdd: Assign IrpPreprocessCallback for IRP_MJ_SHUTDOWN failed, " - "status: 0x%X\n", status)); - - goto Exit; - } - } - - // 4. Set attributes to create Request Context area. - { - //Reuse this structure. - WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, - CDROM_REQUEST_CONTEXT); - attributes.EvtCleanupCallback = RequestEvtCleanup; - - WdfDeviceInitSetRequestAttributes(DeviceInit, - &attributes); - } - - // 5. Register FileObject related callbacks - { - // Add FILE_OBJECT_EXTENSION as the context to the file object. - WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FILE_OBJECT_CONTEXT); - - // Set Entry points for Create and Close.. - - // The framework doesn't sync the file create requests with pnp/power - // state. Re-direct all the file create requests to a dedicated - // queue, which will be purged manually during removal. - WDF_FILEOBJECT_CONFIG_INIT(&fileObjectConfig, - NULL, //CreateQueueEvtIoDefault, - DeviceEvtFileClose, - WDF_NO_EVENT_CALLBACK); // No callback for Cleanup - - fileObjectConfig.FileObjectClass = WdfFileObjectWdfCannotUseFsContexts; - - // Since we are registering file events and fowarding create request - // ourself, we must also set AutoForwardCleanupClose so that cleanup - // and close can also get forwarded. - fileObjectConfig.AutoForwardCleanupClose = WdfTrue; - attributes.SynchronizationScope = WdfSynchronizationScopeNone; - attributes.ExecutionLevel = WdfExecutionLevelPassive; - - // Indicate that file object is optional. - fileObjectConfig.FileObjectClass |= WdfFileObjectCanBeOptional; - - WdfDeviceInitSetFileObjectConfig(DeviceInit, - &fileObjectConfig, - &attributes); - } - - // 6. Initialize device-wide attributes - { - // Declare ourselves as NOT owning power policy. - // The power policy owner in storage stack is port driver. - WdfDeviceInitSetPowerPolicyOwnership(DeviceInit, FALSE); - - // Set other DeviceInit attributes. - WdfDeviceInitSetExclusive(DeviceInit, FALSE); - WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_CD_ROM); - WdfDeviceInitSetCharacteristics(DeviceInit, FILE_REMOVABLE_MEDIA, FALSE); - WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect); - WdfDeviceInitSetPowerPageable(DeviceInit); - - // We require the framework to acquire a remove lock before delivering all IRP types - WDF_REMOVE_LOCK_OPTIONS_INIT(&removeLockOptions, - WDF_REMOVE_LOCK_OPTION_ACQUIRE_FOR_IO); - - WdfDeviceInitSetRemoveLockOptions(DeviceInit, &removeLockOptions); - - // save the PDO for later reference - lowerPdo = WdfFdoInitWdmGetPhysicalDevice(DeviceInit); - - WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, - CDROM_DEVICE_EXTENSION); - - // We have a parallel queue, so WdfSynchronizationScopeNone is our only choice. - attributes.SynchronizationScope = WdfSynchronizationScopeNone; - attributes.ExecutionLevel = WdfExecutionLevelDispatch; - - // Provide a cleanup callback which will release memory allocated with ExAllocatePool* - attributes.EvtCleanupCallback = DeviceEvtCleanup; - } - - // 7. Now, the device can be created. - { - wideDeviceName = ExAllocatePool2(POOL_FLAG_NON_PAGED, - 64 * sizeof(WCHAR), - CDROM_TAG_STRINGS); - - if (wideDeviceName == NULL) - { - status = STATUS_INSUFFICIENT_RESOURCES; - goto Exit; - } - - // Find the lowest device number currently available. - do { - status = RtlStringCchPrintfW((NTSTRSAFE_PWSTR)wideDeviceName, - 64, - L"\\Device\\CdRom%d", - deviceNumber); - - if (!NT_SUCCESS(status)) { - TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, - "DriverEvtDeviceAdd: Format device name failed with error: 0x%X\n", status)); - - goto Exit; - } - - RtlInitUnicodeString(&unicodeDeviceName, wideDeviceName); - - status = WdfDeviceInitAssignName(DeviceInit, &unicodeDeviceName); - if (!NT_SUCCESS(status)) - { - TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, - "DriverEvtDeviceAdd: WdfDeviceInitAssignName() failed with error: 0x%X\n", status)); - - goto Exit; - } - - status = WdfDeviceCreate(&DeviceInit, &attributes, &device); - - deviceNumber++; - - } while (status == STATUS_OBJECT_NAME_COLLISION); - - // When this loop exits the count is inflated by one - fix that. - deviceNumber--; - - if (!NT_SUCCESS(status)) - { - TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, - "DriverEvtDeviceAdd: Can not create a new device, status: 0x%X\n", - status)); - - goto Exit; - } - } - - // 8. Fill up basic Device Extension settings and create a remote I/O target for the next-lower driver. - // The reason why we do not use the local I/O target is because we want to be able to close the - // I/O target on surprise removal. - { - deviceExtension = DeviceGetExtension(device); - - deviceExtension->Version = 0x01; - deviceExtension->Size = sizeof(CDROM_DEVICE_EXTENSION); - - deviceExtension->DeviceObject = WdfDeviceWdmGetDeviceObject(device); - deviceExtension->Device = device; - deviceExtension->DriverExtension = driverExtension; - - deviceExtension->LowerPdo = lowerPdo; - - deviceExtension->DeviceType = FILE_DEVICE_CD_ROM; //Always a FILE_DEVICE_CD_ROM for all device it manages. - deviceExtension->DeviceName = unicodeDeviceName; - - deviceExtension->DeviceNumber = deviceNumber; - } - { - WDF_OBJECT_ATTRIBUTES_INIT(&attributes); - attributes.ParentObject = deviceExtension->Device; - - status = WdfIoTargetCreate(deviceExtension->Device, - &attributes, - &deviceExtension->IoTarget); - - if (!NT_SUCCESS(status)) - { - TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, - "DriverEvtDeviceAdd: Can not create a remote I/O target object, status: 0x%X\n", - status)); - goto Exit; - } - - WDF_IO_TARGET_OPEN_PARAMS_INIT_EXISTING_DEVICE(&ioTargetOpenParams, - WdfDeviceWdmGetAttachedDevice(deviceExtension->Device)); - - status = WdfIoTargetOpen(deviceExtension->IoTarget, - &ioTargetOpenParams); - if (!NT_SUCCESS(status)) - { - TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, - "DriverEvtDeviceAdd: Can not open a remote I/O target for the next-lower device, status: 0x%X\n", - status)); - - WdfObjectDelete(deviceExtension->IoTarget); - deviceExtension->IoTarget = NULL; - - goto Exit; - } - } - - // 9. Claim the device, so that port driver will only accept the commands from CDROM.SYS for this device. - // NOTE: The I/O should be issued after the device is started. But we would like to claim - // the device as soon as possible, so this legacy behavior is kept. - status = DeviceClaimRelease(deviceExtension, FALSE); - - if (!NT_SUCCESS(status)) - { - // Someone already had this device - we're in trouble - goto Exit; - } - else - { - deviceClaimed = TRUE; - } - - // - // CDROM Queueing Structure - // - // a. EvtIoInCallerContext (prior to queueing): - // This event will be used ONLY to forward down IOCTLs that come in at PASSIVE LEVEL - // and need to be forwarded down the stack in the original context. - // - // b. Main input queue: serial queue for main dispatching - // This queue will be used to do all dispatching of requests to serialize - // access to the device. Any request that was previously completed in - // the Dispatch routines will be completed here. Anything requiring device - // I/O will be sent through the serial I/O queue. - // - // 10. Set up IO queues after device being created. - // - { - WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, - WdfIoQueueDispatchSequential); - - queueConfig.PowerManaged = WdfFalse; - -#pragma prefast(push) -#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") -#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") - queueConfig.EvtIoRead = SequentialQueueEvtIoReadWrite; - queueConfig.EvtIoWrite = SequentialQueueEvtIoReadWrite; -#pragma prefast(pop) - - queueConfig.EvtIoDeviceControl = SequentialQueueEvtIoDeviceControl; - queueConfig.EvtIoCanceledOnQueue = SequentialQueueEvtCanceledOnQueue; - - status = WdfIoQueueCreate(device, - &queueConfig, - WDF_NO_OBJECT_ATTRIBUTES, - &(deviceExtension->SerialIOQueue)); - if (!NT_SUCCESS(status)) - { - goto Exit; - } - - // this queue is dedicated for file create requests. - WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchParallel); - - queueConfig.PowerManaged = WdfFalse; - queueConfig.EvtIoDefault = CreateQueueEvtIoDefault; - - //Reuse this structure. - WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, - CDROM_REQUEST_CONTEXT); - - attributes.SynchronizationScope = WdfSynchronizationScopeNone; - attributes.ExecutionLevel = WdfExecutionLevelPassive; - - status = WdfIoQueueCreate(device, - &queueConfig, - &attributes, - &(deviceExtension->CreateQueue)); - - if (!NT_SUCCESS(status)) - { - goto Exit; - } - - // Configure the device to use driver created queue for dispatching create. - status = WdfDeviceConfigureRequestDispatching(device, - deviceExtension->CreateQueue, - WdfRequestTypeCreate); - - if (!NT_SUCCESS(status)) - { - goto Exit; - } - } - - // 11. Set the alignment requirements for the device based on the host adapter requirements. - // - // NOTE: this should have been set when device is attached on device stack, - // by keeping this legacy code, we could avoid issue that this value was not correctly set at that time. - if (deviceExtension->LowerPdo->AlignmentRequirement > deviceExtension->DeviceObject->AlignmentRequirement) - { - WdfDeviceSetAlignmentRequirement(deviceExtension->Device, - deviceExtension->LowerPdo->AlignmentRequirement); - } - - // 12. Initialization of miscellaneous internal properties - - // CDROMs are not partitionable so starting offset is 0. - deviceExtension->StartingOffset.LowPart = 0; - deviceExtension->StartingOffset.HighPart = 0; - - // Set the default geometry for the cdrom to match what NT 4 used. - // these values will be used to compute the cylinder count rather - // than using it's NT 5.0 defaults. - deviceExtension->DiskGeometry.MediaType = RemovableMedia; - deviceExtension->DiskGeometry.TracksPerCylinder = 0x40; - deviceExtension->DiskGeometry.SectorsPerTrack = 0x20; - - deviceExtension->DeviceAdditionalData.ReadWriteRetryDelay100nsUnits = WRITE_RETRY_DELAY_DVD_1x; - - // Clear the SrbFlags and disable synchronous transfers - deviceExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER; - - // Set timeout value in seconds. - deviceExtension->TimeOutValue = DeviceGetTimeOutValueFromRegistry(); - if ((deviceExtension->TimeOutValue > 30 * 60) || // longer than 30 minutes - (deviceExtension->TimeOutValue == 0)) - { - deviceExtension->TimeOutValue = SCSI_CDROM_TIMEOUT; - } - - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, - "DriverEvtDeviceAdd: device timeout is set to %x seconds", - deviceExtension->TimeOutValue - )); - -#if (NTDDI_VERSION >= NTDDI_WIN8) - deviceExtension->IsVolumeOnlinePending = TRUE; - - WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); - - queueConfig.PowerManaged = WdfFalse; - - status = WdfIoQueueCreate(device, - &queueConfig, - WDF_NO_OBJECT_ATTRIBUTES, - &deviceExtension->ManualVolumeReadyQueue); - - if (!NT_SUCCESS(status)) - { - goto Exit; - } -#endif - - // 13. Initialize the stuff related to media locking - WDF_OBJECT_ATTRIBUTES_INIT(&attributes); - attributes.ParentObject = deviceExtension->Device; - status = WdfWaitLockCreate(&attributes, - &deviceExtension->EjectSynchronizationLock); - - deviceExtension->LockCount = 0; - - // 14. Initialize context structures needed for asynchronous release queue and power requests - - if (NT_SUCCESS(status)) - { - status = DeviceInitReleaseQueueContext(deviceExtension); - } - - if (NT_SUCCESS(status)) - { - status = DeviceInitPowerContext(deviceExtension); - } - - // 15. Create external access points other than device name. - if (NT_SUCCESS(status)) - { - status = DeviceCreateWellKnownName(deviceExtension); - } - - // 16. Query session id from the PDO. - if (NT_SUCCESS(status)) - { - status = IoGetDevicePropertyData(deviceExtension->LowerPdo, - &DEVPKEY_Device_SessionId, - 0, - 0, - sizeof(devicePropertySessionId), - &devicePropertySessionId, - &devicePropertySize, - &devicePropertyType); - - if (!NT_SUCCESS(status)) - { - // The device is global. - devicePropertySessionId = INVALID_SESSION; - status = STATUS_SUCCESS; - } - } - - // 17. Register interfaces for this device. - if (NT_SUCCESS(status)) - { - status = DeviceRegisterInterface(deviceExtension, CdRomDeviceInterface); - } - - if (NT_SUCCESS(status)) - { - // If this is a per-session DO, don't register for mount interface so that - // mountmgr will not automatically assign a drive letter. - if (devicePropertySessionId == INVALID_SESSION) - { - status = DeviceRegisterInterface(deviceExtension, MountedDeviceInterface); - } - } - - // 18. Initialize the shutdown/flush lock - if (NT_SUCCESS(status)) - { - WDF_OBJECT_ATTRIBUTES_INIT(&attributes); - attributes.ParentObject = deviceExtension->Device; - - status = WdfWaitLockCreate(&attributes, &deviceExtension->ShutdownFlushWaitLock); - if (!NT_SUCCESS(status)) - { - TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_PNP, - "DriverEvtDeviceAdd: Cannot create shutdown/flush waitlock, status: 0x%X\n", - status)); - } - } - - // 19. Initialize the work item that is used to initiate asynchronous reads/writes - if (NT_SUCCESS(status)) - { - WDF_WORKITEM_CONFIG workItemConfig; - WDF_OBJECT_ATTRIBUTES workItemAttributes; - - WDF_WORKITEM_CONFIG_INIT(&workItemConfig, - ReadWriteWorkItemRoutine - ); - - WDF_OBJECT_ATTRIBUTES_INIT(&workItemAttributes); - workItemAttributes.ParentObject = deviceExtension->Device; - - status = WdfWorkItemCreate(&workItemConfig, - &workItemAttributes, - &deviceExtension->ReadWriteWorkItem - ); - - if (!NT_SUCCESS(status)) - { - TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT, - "DriverEvtDeviceAdd: Cannot create read/write work item, status: 0x%X\n", - status)); - } - } - - // 20. Initialize the work item that is used to process most IOCTLs at PASSIVE_LEVEL. - if (NT_SUCCESS(status)) - { - WDF_WORKITEM_CONFIG workItemConfig; - WDF_OBJECT_ATTRIBUTES workItemAttributes; - - WDF_WORKITEM_CONFIG_INIT(&workItemConfig, - IoctlWorkItemRoutine - ); - - WDF_OBJECT_ATTRIBUTES_INIT(&workItemAttributes); - workItemAttributes.ParentObject = deviceExtension->Device; - - status = WdfWorkItemCreate(&workItemConfig, - &workItemAttributes, - &deviceExtension->IoctlWorkItem - ); - - if (!NT_SUCCESS(status)) - { - TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_INIT, - "DriverEvtDeviceAdd: Cannot create ioctl work item, status: 0x%X\n", - status)); - } - } - - -Exit: - - if (!NT_SUCCESS(status)) - { - FREE_POOL(wideDeviceName); - - if (deviceExtension != NULL) - { - RtlInitUnicodeString(&deviceExtension->DeviceName, NULL); - } - - // Release the device with the port driver, if it was claimed - if ((deviceExtension != NULL) && deviceClaimed) - { - DeviceClaimRelease(deviceExtension, TRUE); - } - deviceClaimed = FALSE; - } - - return status; -} - - -VOID -DeviceEvtCleanup( - _In_ WDFOBJECT Device - ) -/*++ -Routine Description: - - Free all the resources allocated in DriverEvtDeviceAdd. - -Arguments: - - Device - handle to a WDF Device object. - -Return Value: - - VOID. - ---*/ -{ - WDFDEVICE device = (WDFDEVICE)Device; - PCDROM_DEVICE_EXTENSION deviceExtension = NULL; - - PAGED_CODE (); - - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, - "WDFDEVICE %p cleanup: The device is about to be destroyed.\n", - device)); - - deviceExtension = DeviceGetExtension(device); - - FREE_POOL(deviceExtension->DeviceName.Buffer); - RtlInitUnicodeString(&deviceExtension->DeviceName, NULL); - - if (deviceExtension->DeviceAdditionalData.WellKnownName.Buffer != NULL) - { - IoDeleteSymbolicLink(&deviceExtension->DeviceAdditionalData.WellKnownName); - } - - FREE_POOL(deviceExtension->DeviceAdditionalData.WellKnownName.Buffer); - RtlInitUnicodeString(&deviceExtension->DeviceAdditionalData.WellKnownName, NULL); - - return; -} - - -VOID -DeviceEvtSelfManagedIoCleanup( - _In_ WDFDEVICE Device - ) -/*++ - -Routine Description: - - this function is called when the device is removed. - release the ownership of the device, release allocated resources. - -Arguments: - - Device - Handle to device object - -Return Value: - - None. - ---*/ -{ - NTSTATUS status; - PCDROM_DEVICE_EXTENSION deviceExtension = NULL; - - PAGED_CODE (); - - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_PNP, - "DeviceEvtSelfManagedIoCleanup: WDFDEVICE %p is being stopped.\n", - Device)); - - // extract the device and driver extensions - deviceExtension = DeviceGetExtension(Device); - - // Purge unprocessed requests, stop the IO queues. - // Incoming request will be completed with STATUS_INVALID_DEVICE_STATE status. - WdfIoQueuePurge(deviceExtension->SerialIOQueue, WDF_NO_EVENT_CALLBACK, WDF_NO_CONTEXT); - WdfIoQueuePurge(deviceExtension->CreateQueue, WDF_NO_EVENT_CALLBACK, WDF_NO_CONTEXT); - - // Close the IoTarget so that we are sure there are no outstanding I/Os in the stack. - if (deviceExtension->IoTarget) - { - WdfIoTargetClose(deviceExtension->IoTarget); - } - - // Release the device - if (!deviceExtension->SurpriseRemoved) - { - status = DeviceClaimRelease(deviceExtension, TRUE); //status is mainly for debugging. we don't really care. - UNREFERENCED_PARAMETER(status); //defensive coding, avoid PREFAST warning. - } - - // Be sure to flush the DPCs as the READ/WRITE timer routine may still be running - // during device removal. This call may take a while to complete. - KeFlushQueuedDpcs(); - - // Release all the memory that we have allocated. - - DeviceDeallocateMmcResources(Device); - ScratchBuffer_Deallocate(deviceExtension); - RtlZeroMemory(&(deviceExtension->DeviceAdditionalData.Mmc), sizeof(CDROM_MMC_EXTENSION)); - - FREE_POOL(deviceExtension->DeviceDescriptor); - FREE_POOL(deviceExtension->AdapterDescriptor); - FREE_POOL(deviceExtension->PowerDescriptor); - FREE_POOL(deviceExtension->SenseData); - - if (deviceExtension->DeviceAdditionalData.CachedInquiryData != NULL) - { - FREE_POOL(deviceExtension->DeviceAdditionalData.CachedInquiryData); - deviceExtension->DeviceAdditionalData.CachedInquiryDataByteCount = 0; - } - - FREE_POOL(deviceExtension->PrivateFdoData); - - DeviceReleaseMcnResources(deviceExtension); - - DeviceReleaseZPODDResources(deviceExtension); - - // Keep the system-wide CDROM count accurate, as programs use this info to - // know when they have found all the cdroms in a system. - IoGetConfigurationInformation()->CdRomCount--; - - deviceExtension->PartitionLength.QuadPart = 0; - - // All WDF objects related to Device will be automatically released - // when the root object is deleted. No need to release them manually. - - return; -} - -NTSTATUS -DeviceEvtD0Entry( - _In_ WDFDEVICE Device, - _In_ WDF_POWER_DEVICE_STATE PreviousState - ) -/*++ - -Routine Description: - - This function is called when the device is coming back from a lower power state to D0. - This function cannot be placed in a pageable section. - -Arguments: - - Device - Handle to device object - PreviousState - Power state the device was in. - -Return Value: - - NTSTATUS: alway STATUS_SUCCESS - ---*/ -{ - PCDROM_DEVICE_EXTENSION deviceExtension; - NTSTATUS status = STATUS_SUCCESS; - PZERO_POWER_ODD_INFO zpoddInfo = NULL; - STORAGE_IDLE_POWERUP_REASON powerupReason = {0}; - - UNREFERENCED_PARAMETER(PreviousState); - deviceExtension = DeviceGetExtension(Device); - - // Make certain not to do anything before properly initialized - if (deviceExtension->IsInitialized) - { - zpoddInfo = deviceExtension->ZeroPowerODDInfo; - - if (zpoddInfo != NULL) - { - if (zpoddInfo->InZeroPowerState != FALSE) - { - // We just woke up from Zero Power state - zpoddInfo->InZeroPowerState = FALSE; - zpoddInfo->RetryFirstCommand = TRUE; - zpoddInfo->BecomingReadyRetryCount = BECOMING_READY_RETRY_COUNT; - - status = DeviceZPODDGetPowerupReason(deviceExtension, &powerupReason); - - if (NT_SUCCESS(status) && - (powerupReason.PowerupReason == StoragePowerupDeviceAttention)) - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, - "DeviceEvtD0Entry: Device has left zero power state due to eject button pressed\n" - )); - - // This wake-up is caused by user pressing the eject button. - // In case of drawer type, we need to soft eject the tray to emulate the effect. - // Note that the first command to the device after power resumed will - // be terminated with CHECK CONDITION status with sense code 6/29/00, - // but we already have a retry logic to handle this. - if ((zpoddInfo->LoadingMechanism == LOADING_MECHANISM_TRAY) && (zpoddInfo->Load == 0)) // Drawer - { - DeviceSendIoctlAsynchronously(deviceExtension, IOCTL_STORAGE_EJECT_MEDIA, deviceExtension->DeviceObject); - } - } - else - { - // This wake-up is caused by non-cached CDB received or a 3rd-party driver - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, - "DeviceEvtD0Entry: Device has left zero power state due to IO received\n" - )); - - } - } - } - - DeviceEnableMainTimer(deviceExtension); - } - - return STATUS_SUCCESS; -} - -NTSTATUS -DeviceEvtD0Exit( - _In_ WDFDEVICE Device, - _In_ WDF_POWER_DEVICE_STATE TargetState - ) -/*++ - -Routine Description: - - This function is called when the device is entering lower powe state from D0 or it's removed. - We only care about the case of device entering D3. - The purpose of this function is to send SYNC CACHE command and STOP UNIT command if it's necessary. - -Arguments: - - Device - Handle to device object - TargetState - Power state the device is entering. - -Return Value: - - NTSTATUS: alway STATUS_SUCCESS - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - PCDROM_DEVICE_EXTENSION deviceExtension = NULL; - PZERO_POWER_ODD_INFO zpoddInfo = NULL; - - PAGED_CODE (); - - deviceExtension = DeviceGetExtension(Device); - zpoddInfo = deviceExtension->ZeroPowerODDInfo; - - // we only process the situation that the device is going into D3. - if ((TargetState != WdfPowerDeviceD3) && - (TargetState != WdfPowerDeviceD3Final)) - { - return STATUS_SUCCESS; - } - - // Stop the main timer - DeviceDisableMainTimer(deviceExtension); - - // note: do not stop CreateQueue as the create request can be handled by port driver even the device is in D3 status. - - // If initialization was not finished or the device was removed, we cannot interact - // with it device, so we have to exit - if ((!deviceExtension->IsInitialized) || deviceExtension->SurpriseRemoved) - { - return STATUS_SUCCESS; - } - - -#ifdef DBG - #if (WINVER >= 0x0601) - // this API is introduced in Windows7 - { - ULONG secondsRemaining = 0; - BOOLEAN watchdogTimeSupported = FALSE; - - watchdogTimeSupported = PoQueryWatchdogTime(deviceExtension->LowerPdo, &secondsRemaining); - UNREFERENCED_PARAMETER(watchdogTimeSupported); - } - #endif -#endif - - deviceExtension->PowerDownInProgress = TRUE; - - status = PowerContextBeginUse(deviceExtension); - - deviceExtension->PowerContext.Options.PowerDown = TRUE; - - // Step 1. LOCK QUEUE - if (NT_SUCCESS(status) && - (TargetState != WdfPowerDeviceD3Final)) - { - status = DeviceSendPowerDownProcessRequest(deviceExtension, NULL, NULL); - - if (NT_SUCCESS(status)) - { - deviceExtension->PowerContext.Options.LockQueue = TRUE; - } - - // Ignore failure. - status = STATUS_SUCCESS; - } - - deviceExtension->PowerContext.PowerChangeState.PowerDown++; - - // Step 2. QUIESCE QUEUE - if (NT_SUCCESS(status) && - (TargetState != WdfPowerDeviceD3Final)) - { - status = DeviceSendPowerDownProcessRequest(deviceExtension, NULL, NULL); - UNREFERENCED_PARAMETER(status); - // We don't care about the status. - status = STATUS_SUCCESS; - } - - deviceExtension->PowerContext.PowerChangeState.PowerDown++; - - // Step 3. SYNC CACHE command should be sent to drive if the media is currently writable. - if (NT_SUCCESS(status) && - deviceExtension->DeviceAdditionalData.Mmc.WriteAllowed) - { - status = DeviceSendPowerDownProcessRequest(deviceExtension, NULL, NULL); - UNREFERENCED_PARAMETER(status); - status = STATUS_SUCCESS; - } - - deviceExtension->PowerContext.PowerChangeState.PowerDown++; - - // Step 4. STOP UNIT - if (NT_SUCCESS(status) && - !TEST_FLAG(deviceExtension->ScanForSpecialFlags, CDROM_SPECIAL_DISABLE_SPIN_DOWN)) - { - status = DeviceSendPowerDownProcessRequest(deviceExtension, NULL, NULL); - UNREFERENCED_PARAMETER(status); - status = STATUS_SUCCESS; - } - - if (TargetState == WdfPowerDeviceD3Final) - { - // We're done with the power context. - PowerContextEndUse(deviceExtension); - } - - // Bumping the media change count will force the file system to verify the volume when we resume - SET_FLAG(deviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME); - InterlockedIncrement((PLONG)&deviceExtension->MediaChangeCount); - - // If this power down is caused by Zero Power ODD, we should mark the device as in ZPODD mode. - if (zpoddInfo != NULL) - { - zpoddInfo->InZeroPowerState = TRUE; - - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, - "Device has entered zero power state\n" - )); - } - - deviceExtension->PowerDownInProgress = FALSE; - - return STATUS_SUCCESS; -} - - -VOID -DeviceEvtSurpriseRemoval( - _In_ WDFDEVICE Device - ) -/*++ - -Routine Description: - - this function is called when the device is surprisely removed. - Stop all IO queues so that there will be no more request being sent down. - -Arguments: - - Device - Handle to device object - -Return Value: - - None. - ---*/ -{ - PCDROM_DEVICE_EXTENSION deviceExtension = NULL; - - PAGED_CODE(); - - deviceExtension = DeviceGetExtension(Device); - - deviceExtension->SurpriseRemoved = TRUE; - - // Stop the main timer - DeviceDisableMainTimer(deviceExtension); - - // legacy behavior to set partition length to be 0. - deviceExtension->PartitionLength.QuadPart = 0; - - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, - "Surprisely remove a WDFDEVICE %p\n", Device)); - - return; -} - - -VOID -CreateQueueEvtIoDefault( - _In_ WDFQUEUE Queue, - _In_ WDFREQUEST Request - ) -/*++ - -Routine Description: - - this function is called when CREATE irp comes. - setup FileObject context fields, so it can be used to track MCN or exclusive lock/unlock. - -Arguments: - - Queue - Handle to device queue - - Request - the creation request - -Return Value: - - None - ---*/ -{ - WDFFILEOBJECT fileObject = WdfRequestGetFileObject(Request); - WDFDEVICE device = WdfIoQueueGetDevice(Queue); - NTSTATUS status = STATUS_SUCCESS; - PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device); - PFILE_OBJECT_CONTEXT fileObjectContext = NULL; - - PAGED_CODE(); - - if (fileObject == NULL) { - - TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_QUEUE, - "Error: received a file create request with file object set to NULL\n")); - - RequestCompletion(deviceExtension, Request, STATUS_INTERNAL_ERROR, 0); - return; - } - - fileObjectContext = FileObjectGetContext(fileObject); - - // Initialize this WDFFILEOBJECT's context - fileObjectContext->DeviceObject = device; - fileObjectContext->FileObject = fileObject; - fileObjectContext->LockCount = 0; - fileObjectContext->McnDisableCount = 0; - fileObjectContext->EnforceStreamingRead = FALSE; - fileObjectContext->EnforceStreamingWrite = FALSE; - - // send down the create synchronously - status = DeviceSendRequestSynchronously(device, Request, FALSE); - - // Need to complete the request in this routine. - RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request)); - - return; -} - -VOID -DeviceEvtFileClose( - _In_ WDFFILEOBJECT FileObject - ) -/*++ - -Routine Description: - - this function is called when CLOSE irp comes. - clean up MCN / Lock if necessary - -Arguments: - - FileObject - WDF file object created for the irp. - -Return Value: - - None - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - - PAGED_CODE(); - - if (FileObject != NULL) - { - WDFDEVICE device = WdfFileObjectGetDevice(FileObject); - PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device); - PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); - PFILE_OBJECT_CONTEXT fileObjectContext = FileObjectGetContext(FileObject); - - // cleanup locked media tray - status = DeviceCleanupProtectedLocks(deviceExtension, fileObjectContext); - if (!NT_SUCCESS(status)) - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, - "Failed to cleanup protected locks for WDFDEVICE %p, %!STATUS!\n", device, status)); - } - - // cleanup disabled MCN - status = DeviceCleanupDisableMcn(deviceExtension, fileObjectContext); - if (!NT_SUCCESS(status)) - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, - "Failed to disable MCN for WDFDEVICE %p, %!STATUS!\n", device, status)); - } - - // cleanup exclusive access - if (EXCLUSIVE_MODE(cdData) && EXCLUSIVE_OWNER(cdData, FileObject)) - { - status = DeviceUnlockExclusive(deviceExtension, FileObject, FALSE); - if (!NT_SUCCESS(status)) - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, - "Failed to release exclusive lock for WDFDEVICE %p, %!STATUS!\n", device, status)); - } - } - } - - return; -} - -_IRQL_requires_max_(PASSIVE_LEVEL) -NTSTATUS -DeviceCleanupProtectedLocks( - _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, - _In_ PFILE_OBJECT_CONTEXT FileObjectContext - ) -/*++ - -Routine Description: - - this function removes protected locks for the handle - -Arguments: - - DeviceExtension - device context - - FileObject - WDF file object created for the irp. - -Return Value: - - NTSTATUS - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - - PAGED_CODE(); - - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, - "CleanupProtectedLocks called for WDFDEVICE %p, WDFFILEOBJECT %p, locked %d times.\n", - DeviceExtension->Device, FileObjectContext->FileObject, FileObjectContext->LockCount)); - - // Synchronize with ejection and ejection control requests. - WdfWaitLockAcquire(DeviceExtension->EjectSynchronizationLock, NULL); - - // For each secure lock on this handle decrement the secured lock count - // for the FDO. Keep track of the new value. - if (FileObjectContext->LockCount != 0) - { - DeviceExtension->ProtectedLockCount -= FileObjectContext->LockCount; - FileObjectContext->LockCount = 0; - - // If the new lock count has been dropped to zero then issue a lock - // command to the device. - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, - "FDO secured lock count = %d " - "lock count = %d\n", - DeviceExtension->ProtectedLockCount, - DeviceExtension->LockCount)); - - if ((DeviceExtension->ProtectedLockCount == 0) && (DeviceExtension->LockCount == 0)) - { - SCSI_REQUEST_BLOCK srb = {0}; - PCDB cdb = (PCDB) &(srb.Cdb); - - srb.CdbLength = 6; - - cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL; - - // TRUE - prevent media removal. - // FALSE - allow media removal. - cdb->MEDIA_REMOVAL.Prevent = FALSE; - - // Set timeout value. - srb.TimeOutValue = DeviceExtension->TimeOutValue; - status = DeviceSendSrbSynchronously(DeviceExtension->Device, - &srb, - NULL, - 0, - FALSE, - NULL); - - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, - "Allow media removal (unlock) request to drive returned %!STATUS!\n", - status)); - } - } - - WdfWaitLockRelease(DeviceExtension->EjectSynchronizationLock); - - return status; -} - - -_IRQL_requires_max_(APC_LEVEL) -NTSTATUS -DeviceCleanupDisableMcn( - _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, - _In_ PFILE_OBJECT_CONTEXT FileObjectContext - ) -/*++ - -Routine Description: - - cleanup the MCN disable count for the handle - -Arguments: - - DeviceExtension - device context - - FileObject - WDF file object created for the irp. - -Return Value: - - NTSTATUS - ---*/ -{ - PAGED_CODE(); - - TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_INIT, - "CleanupDisableMcn called for WDFDEVICE %p, WDFFILEOBJECT %p, locked %d times.\n", - DeviceExtension->Device, FileObjectContext->FileObject, FileObjectContext->McnDisableCount)); - - // For each secure lock on this handle decrement the secured lock count - // for the FDO. Keep track of the new value. - while (FileObjectContext->McnDisableCount != 0) - { - DeviceEnableMediaChangeDetection(DeviceExtension, FileObjectContext, TRUE); - } - - return STATUS_SUCCESS; -} - -VOID -NormalizeIoctl( - _Inout_ PWDF_REQUEST_PARAMETERS requestParameters - ) -{ - ULONG ioctlCode; - ULONG baseCode; - ULONG functionCode; - - // if this is a class driver ioctl then we need to change the base code - // to IOCTL_STORAGE_BASE so that the switch statement can handle it. - // - // WARNING - currently the scsi class ioctl function codes are between - // 0x200 & 0x300. this routine depends on that fact - ioctlCode = requestParameters->Parameters.DeviceIoControl.IoControlCode; - baseCode = DEVICE_TYPE_FROM_CTL_CODE(ioctlCode); - functionCode = (ioctlCode & (~0xffffc003)) >> 2; - - if ((baseCode == IOCTL_SCSI_BASE) || - (baseCode == IOCTL_DISK_BASE) || - (baseCode == IOCTL_TAPE_BASE) || - (baseCode == IOCTL_DVD_BASE) || - (baseCode == IOCTL_CDROM_BASE)) - //IOCTL_STORAGE_BASE does not need to be converted. - { - if((functionCode >= 0x200) && (functionCode <= 0x300)) - { - ioctlCode = (ioctlCode & 0x0000ffff) | CTL_CODE(IOCTL_STORAGE_BASE, 0, 0, 0); - - TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, - "IOCTL code recalibrate, New ioctl code is %lx\n", - ioctlCode)); - - // Set the code into request parameters, then "requestParameters" needs to be used for dispatch functions. - requestParameters->Parameters.DeviceIoControl.IoControlCode = ioctlCode; - } - } -} - -VOID -DeviceEvtIoInCallerContext( - _In_ WDFDEVICE Device, - _In_ WDFREQUEST Request - ) -/*++ -Routine Description: - - Responds to EvtIoInCallerContext events from KMDF - It calls different functions to process different type of IOCTLs. - -Arguments: - - Device - handle to a WDF Device object - - Request - handle to the incoming WDF Request object - -Return Value: - - VOID. - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); - PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); - WDF_REQUEST_PARAMETERS requestParameters; - - requestContext->DeviceExtension = deviceExtension; - - // set the received time - RequestSetReceivedTime(Request); - - // get the request parameters - WDF_REQUEST_PARAMETERS_INIT(&requestParameters); - WdfRequestGetParameters(Request, &requestParameters); - - if (requestParameters.Type == WdfRequestTypeDeviceControl) - { - BOOLEAN processed = FALSE; - PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); - PMEDIA_CHANGE_DETECTION_INFO info = deviceExtension->MediaChangeDetectionInfo; - - if (requestParameters.Parameters.DeviceIoControl.IoControlCode != IOCTL_MCN_SYNC_FAKE_IOCTL) - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "Receiving IOCTL: %lx\n", - requestParameters.Parameters.DeviceIoControl.IoControlCode)); - } - else - { - TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_IOCTL, - "Receiving IOCTL: %lx\n", - requestParameters.Parameters.DeviceIoControl.IoControlCode)); - } - - // If the device is in exclusive mode, check whether the request is from - // the handle that locked the device. - if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request))) - { - BOOLEAN isBlocked = FALSE; - - status = RequestIsIoctlBlockedByExclusiveAccess(Request, &isBlocked); - UNREFERENCED_PARAMETER(status); //defensive coding, avoid PREFAST warning. - - if (isBlocked) - { - if ((requestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_EVENT_NOTIFICATION) && - (info != NULL) && (info->AsynchronousNotificationSupported != FALSE)) - { - // If AN is supported and we receive a signal but we can't send down GESN - // due to exclusive lock, we should save it and fire a GESN when it's unlocked. - // We just need true/false here and don't need count because we will keep sending - // GESN until we deplete all events. - info->ANSignalPendingDueToExclusiveLock = TRUE; - } - - TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, - "Access Denied! Device in exclusive mode.Failing Ioctl %lx\n", - requestParameters.Parameters.DeviceIoControl.IoControlCode)); - RequestCompletion(deviceExtension, Request, STATUS_ACCESS_DENIED, 0); - - return; - } - } - - NormalizeIoctl(&requestParameters); - - // 1. All requests that don't need to access device can be processed immediately - if (!processed) - { - processed = RequestDispatchProcessDirectly(Device, Request, requestParameters); - } - - // 2. Requests that should be put in sequential queue. - if (!processed) - { - processed = RequestDispatchToSequentialQueue(Device, Request, requestParameters); - } - - // 3. Requests that need to be processed sequentially and in caller's context. - if (!processed) - { - processed = RequestDispatchSyncWithSequentialQueue(Device, Request, requestParameters); - } - - // 4. Special requests that needs different process in different cases. - if (!processed) - { - processed = RequestDispatchSpecialIoctls(Device, Request, requestParameters); - } - - // 5. This is default behavior for unknown IOCTLs. To pass it to lower level. - if (!processed) - { - processed = RequestDispatchUnknownRequests(Device, Request, requestParameters); - } - - // All requests should be processed already. - NT_ASSERT(processed); - UNREFERENCED_PARAMETER(processed); //defensive coding, avoid PREFAST warning. - } - else if (requestParameters.Type == WdfRequestTypeDeviceControlInternal) - { - RequestProcessInternalDeviceControl(Request, deviceExtension); - } - else - { - // Requests other than IOCTLs will be forwarded to default queue. - status = WdfDeviceEnqueueRequest(Device, Request); - if (!NT_SUCCESS(status)) - { - RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request)); - } - } - - return; -} - - -BOOLEAN -RequestDispatchProcessDirectly( - _In_ WDFDEVICE Device, - _In_ WDFREQUEST Request, - _In_ WDF_REQUEST_PARAMETERS RequestParameters - ) -/*++ -Routine Description: - - These requests can be processed in a non-serialized manner, most of them don't need to access device. - -Arguments: - - Device - handle to a WDF Device object - - Request - handle to the incoming WDF Request object - - RequestParameters - request parameters - -Return Value: - - BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function). - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - BOOLEAN processed = FALSE; - size_t dataLength = 0; - - PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); - ULONG ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; - - switch (ioctlCode) - { - - case IOCTL_CDROM_GET_INQUIRY_DATA: - { - status = RequestHandleGetInquiryData(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; // complete the irp - } - - case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: - { - status = RequestHandleGetMediaTypeEx(deviceExtension, Request, &dataLength); - - processed = TRUE; - break; // complete the irp - } - - case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: - { - status = RequestHandleMountQueryUniqueId(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; // complete the irp - } - - case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: - { - status = RequestHandleMountQueryDeviceName(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; // complete the irp - } - - case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME: - { - status = RequestHandleMountQuerySuggestedLinkName(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; // complete the irp - } - - case IOCTL_STORAGE_GET_DEVICE_NUMBER: - { - status = RequestHandleGetDeviceNumber(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; // complete the irp - } - - case IOCTL_STORAGE_GET_HOTPLUG_INFO: - { - status = RequestHandleGetHotPlugInfo(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; // complete the irp - } - - case IOCTL_STORAGE_SET_HOTPLUG_INFO: - { - status = RequestHandleSetHotPlugInfo(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; // complete the irp - } - - case IOCTL_STORAGE_EVENT_NOTIFICATION: - { - status = RequestHandleEventNotification(deviceExtension, Request, &RequestParameters, &dataLength); - - processed = TRUE; - break; // complete the irp - } - -#if (NTDDI_VERSION >= NTDDI_WIN8) - case IOCTL_VOLUME_ONLINE: - { - // - // Mount manager and volume manager will - // follow this online with a post online - // but other callers may not. In those - // cases, we process this request right - // away. We approximate that these other - // callers are from user mode - // - - if (WdfRequestGetRequestorMode(Request) == KernelMode) - { - processed = TRUE; - } - break; - } -#endif - - default: - { - processed = FALSE; - break; - } - - } //end of switch (ioctlCode) - - if (processed) - { - UCHAR currentStackLocationFlags = 0; - currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request); - - if ((status == STATUS_VERIFY_REQUIRED) && - (currentStackLocationFlags & SL_OVERRIDE_VERIFY_VOLUME)) - { - // If the status is verified required and this request - // should bypass verify required then retry the request. - status = STATUS_IO_DEVICE_ERROR; - UNREFERENCED_PARAMETER(status); // disables prefast warning; defensive coding... - - processed = RequestDispatchProcessDirectly(Device, Request, RequestParameters); - } - else - { - // Complete the request after processing it. - RequestCompletion(deviceExtension, Request, status, dataLength); - } - } - - return processed; -} - - -BOOLEAN -RequestDispatchToSequentialQueue( - _In_ WDFDEVICE Device, - _In_ WDFREQUEST Request, - _In_ WDF_REQUEST_PARAMETERS RequestParameters - ) -/*++ -Routine Description: - - These requests can be processed in a non-serialized manner, most of them don't need to access device. - -Arguments: - - Device - handle to a WDF Device object - - Request - handle to the incoming WDF Request object - - RequestParameters - request parameters - -Return Value: - - BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function). - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - BOOLEAN processed = FALSE; - size_t dataLength = 0; - BOOLEAN inZeroPowerState = FALSE; - - PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); - ULONG ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; - PZERO_POWER_ODD_INFO zpoddInfo = deviceExtension->ZeroPowerODDInfo; - - if ((zpoddInfo != NULL) && - (zpoddInfo->InZeroPowerState != FALSE)) - { - inZeroPowerState = TRUE; - } - - switch (ioctlCode) - { - - case IOCTL_CDROM_RAW_READ: - { - status = RequestValidateRawRead(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: - case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: Get drive geometryEx\n")); - if ( RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < - (ULONG)FIELD_OFFSET(DISK_GEOMETRY_EX, Data)) - { - status = STATUS_BUFFER_TOO_SMALL; - dataLength = FIELD_OFFSET(DISK_GEOMETRY_EX, Data); - } - else if (inZeroPowerState != FALSE) - { - status = STATUS_NO_MEDIA_IN_DEVICE; - } - else - { - status = STATUS_SUCCESS; - } - - processed = TRUE; - break; - } - - case IOCTL_DISK_GET_DRIVE_GEOMETRY: - case IOCTL_CDROM_GET_DRIVE_GEOMETRY: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: Get drive geometry\n")); - if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < - sizeof(DISK_GEOMETRY)) - { - status = STATUS_BUFFER_TOO_SMALL; - dataLength = sizeof(DISK_GEOMETRY); - } - else if (inZeroPowerState != FALSE) - { - status = STATUS_NO_MEDIA_IN_DEVICE; - } - else - { - status = STATUS_SUCCESS; - } - - processed = TRUE; - break; - } - - case IOCTL_CDROM_READ_TOC_EX: - { - status = RequestValidateReadTocEx(deviceExtension, Request, RequestParameters, &dataLength); - - if (inZeroPowerState != FALSE) - { - status = STATUS_NO_MEDIA_IN_DEVICE; - } - - processed = TRUE; - break; - } - - case IOCTL_CDROM_READ_TOC: - { - status = RequestValidateReadToc(deviceExtension, RequestParameters, &dataLength); - - if (inZeroPowerState != FALSE) - { - status = STATUS_NO_MEDIA_IN_DEVICE; - } - - processed = TRUE; - break; - } - - case IOCTL_CDROM_GET_LAST_SESSION: - { - status = RequestValidateGetLastSession(deviceExtension, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_CDROM_PLAY_AUDIO_MSF: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: Play audio MSF\n")); - - if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < - sizeof(CDROM_PLAY_AUDIO_MSF)) - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - else - { - status = STATUS_SUCCESS; - } - - processed = TRUE; - break; - } - - case IOCTL_CDROM_SEEK_AUDIO_MSF: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: Seek audio MSF\n")); - - if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < - sizeof(CDROM_SEEK_AUDIO_MSF)) - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - else - { - status = STATUS_SUCCESS; - } - - processed = TRUE; - break; - } - - case IOCTL_CDROM_PAUSE_AUDIO: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: Pause audio\n")); - - status = STATUS_SUCCESS; - processed = TRUE; - break; - } - - case IOCTL_CDROM_RESUME_AUDIO: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: Resume audio\n")); - - status = STATUS_SUCCESS; - processed = TRUE; - break; - } - - case IOCTL_CDROM_READ_Q_CHANNEL: - { - status = RequestValidateReadQChannel(Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_CDROM_GET_VOLUME: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: Get volume control\n")); - - if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < - sizeof(VOLUME_CONTROL)) - { - status = STATUS_BUFFER_TOO_SMALL; - dataLength = sizeof(VOLUME_CONTROL); - } - else - { - status = STATUS_SUCCESS; - } - - processed = TRUE; - break; - } - - case IOCTL_CDROM_SET_VOLUME: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: Set volume control\n")); - - if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < - sizeof(VOLUME_CONTROL)) - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - else - { - status = STATUS_SUCCESS; - } - - processed = TRUE; - break; - } - - case IOCTL_CDROM_STOP_AUDIO: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: Stop audio\n")); - - status = STATUS_SUCCESS; - processed = TRUE; - break; - } - - case IOCTL_STORAGE_CHECK_VERIFY: - case IOCTL_STORAGE_CHECK_VERIFY2: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: [%p] Check Verify\n", Request)); - - // Following check will let the condition "OutputBufferLength == 0" pass. - // Since it's legacy behavior in classpnp, we need to keep it. - if ((RequestParameters.Parameters.DeviceIoControl.OutputBufferLength > 0) && - (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))) - { - status = STATUS_BUFFER_TOO_SMALL; - dataLength = sizeof(ULONG); - } - else if (inZeroPowerState != FALSE) - { - status = STATUS_NO_MEDIA_IN_DEVICE; - } - else - { - status = STATUS_SUCCESS; - } - - processed = TRUE; - break; - } - - case IOCTL_DVD_GET_REGION: - { - // validation will be done when process it. - status = STATUS_SUCCESS; - processed = TRUE; - break; - } - - case IOCTL_DVD_READ_STRUCTURE: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_READ_STRUCTURE\n", Request)); - - status = RequestValidateDvdReadStructure(deviceExtension, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_DVD_READ_KEY: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_READ_KEY\n", Request)); - - status = RequestValidateDvdReadKey(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_DVD_START_SESSION: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_START_SESSION\n", Request)); - - status = RequestValidateDvdStartSession(deviceExtension, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_DVD_SEND_KEY: - case IOCTL_DVD_SEND_KEY2: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_SEND_KEY\n", Request)); - - status = RequestValidateDvdSendKey(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_STORAGE_SET_READ_AHEAD: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: [%p] SetReadAhead\n", Request)); - - if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < - sizeof(STORAGE_SET_READ_AHEAD)) - { - status = STATUS_INVALID_PARAMETER; - } - else - { - status = STATUS_SUCCESS; - } - - processed = TRUE; - break; - } - - case IOCTL_DISK_IS_WRITABLE: - { - status = STATUS_SUCCESS; - - processed = TRUE; - break; - } - - case IOCTL_DISK_GET_DRIVE_LAYOUT: - { - ULONG requiredSize = 0; - - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: Get drive layout\n")); - - requiredSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[1]); - - if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < - requiredSize) - { - status = STATUS_BUFFER_TOO_SMALL; - dataLength = requiredSize; - } - else - { - status = STATUS_SUCCESS; - } - - processed = TRUE; - break; - } - - case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: - { - ULONG requiredSize = 0; - - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: Get drive layoutEx\n")); - - requiredSize = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[1]); - - if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < - requiredSize) - { - status = STATUS_BUFFER_TOO_SMALL; - dataLength = requiredSize; - } - else - { - status = STATUS_SUCCESS; - } - - processed = TRUE; - break; - } - - case IOCTL_DISK_GET_PARTITION_INFO: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: Get Partition Info\n")); - - if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < - sizeof(PARTITION_INFORMATION)) - { - status = STATUS_BUFFER_TOO_SMALL; - dataLength = sizeof(PARTITION_INFORMATION); - } - else - { - status = STATUS_SUCCESS; - } - - processed = TRUE; - break; - } - - case IOCTL_DISK_GET_PARTITION_INFO_EX: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: Get Partition InfoEx\n")); - - if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < - sizeof(PARTITION_INFORMATION_EX)) - { - status = STATUS_BUFFER_TOO_SMALL; - dataLength = sizeof(PARTITION_INFORMATION_EX); - } - else - { - status = STATUS_SUCCESS; - } - - processed = TRUE; - break; - } - - case IOCTL_DISK_VERIFY: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: IOCTL_DISK_VERIFY to device %p through request %p\n", - Device, - Request)); - - if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < - sizeof(VERIFY_INFORMATION)) - { - status = STATUS_INVALID_PARAMETER; - } - else - { - status = STATUS_SUCCESS; - } - - processed = TRUE; - break; - } - - case IOCTL_DISK_GET_LENGTH_INFO: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: Disk Get Length InfoEx\n")); - - if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < - sizeof(GET_LENGTH_INFORMATION)) - { - status = STATUS_BUFFER_TOO_SMALL; - dataLength = sizeof(GET_LENGTH_INFORMATION); - } - else if (inZeroPowerState != FALSE) - { - status = STATUS_NO_MEDIA_IN_DEVICE; - } - else - { - status = STATUS_SUCCESS; - } - - processed = TRUE; - break; - } - - case IOCTL_CDROM_GET_CONFIGURATION: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_GET_CONFIGURATION\n", Request)); - - status = RequestValidateGetConfiguration(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_CDROM_SET_SPEED: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_SET_SPEED\n", Request)); - - status = RequestValidateSetSpeed(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_DVD_END_SESSION: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: [%p] IOCTL_DVD_END_SESSION\n", Request)); - - status = RequestValidateDvdEndSession(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_AACS_END_SESSION: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: [%p] IOCTL_AACS_END_SESSION\n", Request)); - - status = RequestValidateAacsEndSession(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_AACS_READ_MEDIA_KEY_BLOCK: - { - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, - "AACS: Querying full MKB with bufferSize of %x bytes\n", - (int)RequestParameters.Parameters.DeviceIoControl.OutputBufferLength - )); - - status = RequestValidateAacsReadMediaKeyBlock(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_AACS_START_SESSION: - { - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, - "AACS: Requesting AGID\n" - )); - - status = RequestValidateAacsStartSession(deviceExtension, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_AACS_SEND_CERTIFICATE: - { - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, - "AACS: Sending host certificate to drive\n" - )); - - status = RequestValidateAacsSendCertificate(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_AACS_GET_CERTIFICATE: - { - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, - "AACS: Querying drive certificate\n" - )); - - status = RequestValidateAacsGetCertificate(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_AACS_GET_CHALLENGE_KEY: - { - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, - "AACS: Querying drive challenge key\n" - )); - - status = RequestValidateAacsGetChallengeKey(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_AACS_SEND_CHALLENGE_KEY: - { - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, - "AACS: Sending drive challenge key\n" - )); - - status = RequestValidateAacsSendChallengeKey(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_AACS_READ_VOLUME_ID: - { - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, - "AACS: Reading volume ID\n" - )); - - status = RequestValidateAacsReadVolumeId(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_AACS_READ_SERIAL_NUMBER: - { - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, - "AACS: Reading Serial Number\n" - )); - - status = RequestValidateAacsReadSerialNumber(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_AACS_READ_MEDIA_ID: - { - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, - "AACS: Reading media ID\n" - )); - - status = RequestValidateAacsReadMediaId(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_AACS_READ_BINDING_NONCE: - case IOCTL_AACS_GENERATE_BINDING_NONCE: - { - if (ioctlCode == IOCTL_AACS_GENERATE_BINDING_NONCE) - { - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, - "AACS: Generating new binding nonce\n" - )); - } - else - { - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, - "AACS: Reading existing binding nonce\n" - )); - } - - status = RequestValidateAacsBindingNonce(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_CDROM_ENABLE_STREAMING: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_ENABLE_STREAMING\n", Request)); - - status = RequestValidateEnableStreaming(Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_CDROM_SEND_OPC_INFORMATION: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_SEND_OPC_INFORMATION\n", Request)); - - status = RequestValidateSendOpcInformation(Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_CDROM_GET_PERFORMANCE: - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "RequestDispatchToSequentialQueue: [%p] IOCTL_CDROM_GET_PERFORMANCE\n", Request)); - - status = RequestValidateGetPerformance(Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_STORAGE_MEDIA_REMOVAL: - case IOCTL_STORAGE_EJECTION_CONTROL: - { - if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength < - sizeof(PREVENT_MEDIA_REMOVAL)) - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - else - { - status = STATUS_SUCCESS; - } - - processed = TRUE; - break; // complete the irp - } - - case IOCTL_STORAGE_MCN_CONTROL: - { - if(RequestParameters.Parameters.DeviceIoControl.InputBufferLength < - sizeof(PREVENT_MEDIA_REMOVAL)) - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - else - { - status = STATUS_SUCCESS; - } - - processed = TRUE; - break; // complete the irp - } - - case IOCTL_STORAGE_RESERVE: - case IOCTL_STORAGE_RELEASE: - { - // there is no validate check currently. - status = STATUS_SUCCESS; - processed = TRUE; - break; - } - - case IOCTL_STORAGE_PERSISTENT_RESERVE_IN: - case IOCTL_STORAGE_PERSISTENT_RESERVE_OUT: - { - status = RequestValidatePersistentReserve(deviceExtension, Request, RequestParameters, &dataLength); - - processed = TRUE; - break; - } - - case IOCTL_STORAGE_EJECT_MEDIA: - case IOCTL_STORAGE_LOAD_MEDIA: - case IOCTL_STORAGE_LOAD_MEDIA2: - { - status = STATUS_SUCCESS; - - processed = TRUE; - break; // complete the irp - } - - case IOCTL_STORAGE_FIND_NEW_DEVICES: - { - // process it. - IoInvalidateDeviceRelations(deviceExtension->LowerPdo, BusRelations); - - status = STATUS_SUCCESS; - - processed = TRUE; - break; // complete the irp - } - - case IOCTL_STORAGE_READ_CAPACITY: - { - if (RequestParameters.Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_READ_CAPACITY)) - { - dataLength = sizeof(STORAGE_READ_CAPACITY); - status = STATUS_BUFFER_TOO_SMALL; - } - else if (inZeroPowerState != FALSE) - { - status = STATUS_NO_MEDIA_IN_DEVICE; - } - else - { - status = STATUS_SUCCESS; - } - - processed = TRUE; - break; // complete the irp - } - - case IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT: - { - // for disk.sys only in original classpnp - status = STATUS_NOT_SUPPORTED; - - processed = TRUE; - break; // complete the irp - } - -#if (NTDDI_VERSION >= NTDDI_WIN8) - case IOCTL_DISK_ARE_VOLUMES_READY: - { - // this request doesn't access device at all, so seemingly it can be processed - // directly; however, in case volume online is not received, we will need to - // park these requests in a queue, and the only way a request can be queued is - // if the request came out of another queue. - status = STATUS_SUCCESS; - - processed = TRUE; - break; - } - - case IOCTL_VOLUME_ONLINE: - case IOCTL_VOLUME_POST_ONLINE: - { - status = STATUS_SUCCESS; - - processed = TRUE; - break; - } -#endif - - default: - { - processed = FALSE; - break; - } - } //end of switch (ioctlCode) - - if (processed) - { - UCHAR currentStackLocationFlags = 0; - currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request); - - if ((status == STATUS_VERIFY_REQUIRED) && - (currentStackLocationFlags & SL_OVERRIDE_VERIFY_VOLUME)) - { - // If the status is verified required and this request - // should bypass verify required then retry the request. - status = STATUS_IO_DEVICE_ERROR; - UNREFERENCED_PARAMETER(status); // disables prefast warning; defensive coding... - - processed = RequestDispatchToSequentialQueue(Device, Request, RequestParameters); - } - else - { - if (NT_SUCCESS(status)) - { - // Forward the request to serialized queue. - status = WdfDeviceEnqueueRequest(Device, Request); - } - - if (!NT_SUCCESS(status)) - { - // Validation failed / forward failed, complete the request. - RequestCompletion(deviceExtension, Request, status, dataLength); - } - } - } - - return processed; -} - - -BOOLEAN -RequestDispatchSyncWithSequentialQueue( - _In_ WDFDEVICE Device, - _In_ WDFREQUEST Request, - _In_ WDF_REQUEST_PARAMETERS RequestParameters - ) -/*++ -Routine Description: - - These requests need to stay in caller's context and be processed in serialized manner. - -Arguments: - - Device - handle to a WDF Device object - - Request - handle to the incoming WDF Request object - - RequestParameters - request parameters - -Return Value: - - BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function). - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - BOOLEAN processed = FALSE; - size_t dataLength = 0; - - PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); - ULONG ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; - - switch (ioctlCode) - { - - case IOCTL_CDROM_EXCLUSIVE_ACCESS: - { - //1. Validate - status = RequestValidateExclusiveAccess(Request, RequestParameters, &dataLength); - - //2. keep the request in serialized manner and stay in user's context. - if (NT_SUCCESS(status)) - { - PCDROM_EXCLUSIVE_ACCESS exclusiveAccess = NULL; - - status = WdfRequestRetrieveInputBuffer(Request, - RequestParameters.Parameters.DeviceIoControl.InputBufferLength, - &exclusiveAccess, - NULL); - - if (NT_SUCCESS(status)) - { - // do not need to check "status" as it passed validation and cannot fail in WdfRequestRetrieveInputBuffer() - switch (exclusiveAccess->RequestType) - { - - case ExclusiveAccessQueryState: - { - status = RequestSetContextFields(Request, RequestHandleExclusiveAccessQueryLockState); - break; - } - - case ExclusiveAccessLockDevice: - { - status = RequestSetContextFields(Request, RequestHandleExclusiveAccessLockDevice); - break; - } - - case ExclusiveAccessUnlockDevice: - { - status = RequestSetContextFields(Request, RequestHandleExclusiveAccessUnlockDevice); - break; - } - default: - { - // already valicated in RequestValidateExclusiveAccess() - NT_ASSERT(FALSE); - break; - } - } - } - - if (NT_SUCCESS(status)) - { - // now, put the special synchronization information into the context - status = RequestSynchronizeProcessWithSerialQueue(Device, Request); - - // "status" is used for debugging in above statement, reset to success to avoid further work in this function. - status = STATUS_SUCCESS; - } - } - - processed = TRUE; - break; // complete the irp - } - - default: - { - processed = FALSE; - break; - } - } //end of switch (ioctlCode) - - // Following process is only valid if the request is not really processed. (failed in validation) - if (processed && !NT_SUCCESS(status)) - { - UCHAR currentStackLocationFlags = 0; - currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request); - - if ((status == STATUS_VERIFY_REQUIRED) && - (currentStackLocationFlags & SL_OVERRIDE_VERIFY_VOLUME)) - { - // - // If the status is verified required and this request - // should bypass verify required then retry the request. - // - status = STATUS_IO_DEVICE_ERROR; - UNREFERENCED_PARAMETER(status); // disables prefast warning; defensive coding... - - processed = RequestDispatchSyncWithSequentialQueue(Device, Request, RequestParameters); - } - else - { - // Validation failed / forward failed, complete the request. - RequestCompletion(deviceExtension, Request, status, dataLength); - } - } - - return processed; -} - - -BOOLEAN -RequestDispatchSpecialIoctls( - _In_ WDFDEVICE Device, - _In_ WDFREQUEST Request, - _In_ WDF_REQUEST_PARAMETERS RequestParameters - ) -/*++ -Routine Description: - - These requests need to be processed in different manner according to input parameters - -Arguments: - - Device - handle to a WDF Device object - - Request - handle to the incoming WDF Request object - - RequestParameters - request parameters - -Return Value: - - BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function). - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - BOOLEAN processed = FALSE; - size_t dataLength = 0; - BOOLEAN requestCompleted = FALSE; - - PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); - PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); - ULONG ioctlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode; - - switch (ioctlCode) - { - case IOCTL_SCSI_PASS_THROUGH: - case IOCTL_SCSI_PASS_THROUGH_DIRECT: - case IOCTL_SCSI_PASS_THROUGH_EX: - case IOCTL_SCSI_PASS_THROUGH_DIRECT_EX: - { - // SPTI is considered special case as we need to set the MinorFunction before pass to low level. - -#if defined (_WIN64) - if (WdfRequestIsFrom32BitProcess(Request)) - { - if ((ioctlCode == IOCTL_SCSI_PASS_THROUGH) || (ioctlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)) - { - if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH32)) - { - status = STATUS_INVALID_PARAMETER; - } - } - else - { - if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH32_EX)) - { - status = STATUS_INVALID_PARAMETER; - } - } - } - else -#endif - { - if ((ioctlCode == IOCTL_SCSI_PASS_THROUGH) || (ioctlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)) - { - if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH)) - { - status = STATUS_INVALID_PARAMETER; - } - } - else - { - if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH_EX)) - { - status = STATUS_INVALID_PARAMETER; - } - } - } - - if (!NT_SUCCESS(status)) - { - // validation failed. - RequestCompletion(deviceExtension, Request, status, dataLength); - } - else - { - // keep the request in serialized manner and stay in user's context. - status = RequestSetContextFields(Request, RequestHandleScsiPassThrough); - - if (NT_SUCCESS(status)) - { - status = RequestSynchronizeProcessWithSerialQueue(Device, Request); - } - else - { - RequestCompletion(deviceExtension, Request, status, 0); - } - } - - requestCompleted = TRUE; - processed = TRUE; - break; - } - - case IOCTL_STORAGE_QUERY_PROPERTY: - { - if (RequestParameters.Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_PROPERTY_QUERY)) - { - status = STATUS_INFO_LENGTH_MISMATCH; - } - else - { - PSTORAGE_PROPERTY_QUERY inputBuffer = NULL; - - status = WdfRequestRetrieveInputBuffer(Request, - RequestParameters.Parameters.DeviceIoControl.InputBufferLength, - &inputBuffer, - NULL); - - if (NT_SUCCESS(status)) - { - if (!EXCLUSIVE_MODE(cdData) || // not locked - EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request)) || // request is from lock owner - (inputBuffer->QueryType == PropertyExistsQuery)) // request not access device - { - if (inputBuffer->PropertyId == StorageDeviceUniqueIdProperty) - { - // previously handled in classpnp - // keep the request in serialized manner and stay in user's context. - status = RequestSetContextFields(Request, RequestHandleQueryPropertyDeviceUniqueId); - - if (NT_SUCCESS(status)) - { - status = RequestSynchronizeProcessWithSerialQueue(Device, Request); - // remeber that the request has been completed. - requestCompleted = TRUE; - } - } - else if (inputBuffer->PropertyId == StorageDeviceWriteCacheProperty) - { - // previously handled in classpnp - // keep the request in serialized manner and stay in user's context. - status = RequestSetContextFields(Request, RequestHandleQueryPropertyWriteCache); - - if (NT_SUCCESS(status)) - { - status = RequestSynchronizeProcessWithSerialQueue(Device, Request); - // remeber that the request has been completed. - requestCompleted = TRUE; - } - } - else - { - // Pass to port driver for handling - RequestDispatchUnknownRequests(Device, Request, RequestParameters); - - // remeber that the request has been completed. - requestCompleted = TRUE; - } - } - else - { - // If cached data exists, return cached data. Otherwise, fail the request. - if ((inputBuffer->QueryType == PropertyStandardQuery) && - ((inputBuffer->PropertyId == StorageDeviceProperty) || (inputBuffer->PropertyId == StorageAdapterProperty)) ) - { - status = RequestHandleQueryPropertyRetrieveCachedData(deviceExtension, Request, RequestParameters, &dataLength); - } - else - { - status = STATUS_ACCESS_DENIED; - } - } - } - } - - processed = TRUE; - break; - } - - // this IOCTL is a fake one, used for MCN process sync-ed with serial queue. - case IOCTL_MCN_SYNC_FAKE_IOCTL: - { - PIRP irp = WdfRequestWdmGetIrp(Request); - - if ((deviceExtension->MediaChangeDetectionInfo != NULL) && - (irp == deviceExtension->MediaChangeDetectionInfo->MediaChangeSyncIrp) && - (WdfRequestGetRequestorMode(Request) == KernelMode) && - (RequestParameters.Parameters.Others.Arg1 == RequestSetupMcnSyncIrp) && - (RequestParameters.Parameters.Others.Arg2 == RequestSetupMcnSyncIrp) && - (RequestParameters.Parameters.Others.Arg4 == RequestSetupMcnSyncIrp)) - { - // This is the requset we use to sync Media Change Detection with sequential queue. - status = WdfDeviceEnqueueRequest(Device, Request); - - if (!NT_SUCCESS(status)) - { - RequestCompletion(deviceExtension, Request, status, dataLength); - } - - requestCompleted = TRUE; - processed = TRUE; - } - else - { - // process as an unknown request. - processed = FALSE; - } - break; - } - - default: - { - processed = FALSE; - break; - } - } //end of switch (ioctlCode) - - if (processed && !requestCompleted) - { - UCHAR currentStackLocationFlags = 0; - currentStackLocationFlags = RequestGetCurrentStackLocationFlags(Request); - - if ((status == STATUS_VERIFY_REQUIRED) && - (currentStackLocationFlags & SL_OVERRIDE_VERIFY_VOLUME)) - { - // If the status is verified required and this request - // should bypass verify required then retry the request. - status = STATUS_IO_DEVICE_ERROR; - UNREFERENCED_PARAMETER(status); // disables prefast warning; defensive coding... - - processed = RequestDispatchSpecialIoctls(Device, Request, RequestParameters); - } - else - { - RequestCompletion(deviceExtension, Request, status, dataLength); - } - } - - return processed; -} - - -BOOLEAN -RequestDispatchUnknownRequests( - _In_ WDFDEVICE Device, - _In_ WDFREQUEST Request, - _In_ WDF_REQUEST_PARAMETERS RequestParameters - ) -/*++ -Routine Description: - - All unknown requests will be pass to lower level driver. - If IRQL is PASSIVE_LEVEL, the request will be serialized; - Otherwise, it'll be sent and forget. - -Arguments: - - Device - handle to a WDF Device object - - Request - handle to the incoming WDF Request object - - RequestParameters - request parameters - -Return Value: - - BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function). - ---*/ -{ - NTSTATUS status = STATUS_UNSUCCESSFUL; - PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); - - ULONG baseCode = DEVICE_TYPE_FROM_CTL_CODE(RequestParameters.Parameters.DeviceIoControl.IoControlCode); - - if ((KeGetCurrentIrql() != PASSIVE_LEVEL) || - (baseCode == FILE_DEVICE_ACPI)) - { - // 1. When IRQL is higher than PASSIVE_LEVEL, - // 2. ataport sends IOCTL_ACPI_ASYNC_EVAL_METHOD before queue starts, - // send request directly to lower driver. - status = RequestHandleUnknownIoctl(Device, Request); - } - else - { - // keep the request in serialized manner and stay in user's context. - status = RequestSetContextFields(Request, RequestHandleUnknownIoctl); - - if (NT_SUCCESS(status)) - { - status = RequestSynchronizeProcessWithSerialQueue(Device, Request); - } - else - { - RequestCompletion(deviceExtension, Request, status, 0); - } - } - - UNREFERENCED_PARAMETER(status); //defensive coding, avoid PREFAST warning. - - // All unknown IOCTLs are processed in this function. - return TRUE; //processed -} - -VOID -RequestProcessInternalDeviceControl( - _In_ WDFREQUEST Request, - _In_ PCDROM_DEVICE_EXTENSION DeviceExtension - ) -/*++ -Routine Description: - - all internal IOCTL will be send to lower driver asynchronously. - -Arguments: - - Request - handle to the incoming WDF Request object - DeviceExtension - device extension structure - -Return Value: - - None - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - PIRP irp = NULL; - PIO_STACK_LOCATION irpStack = NULL; - PIO_STACK_LOCATION nextStack = NULL; - BOOLEAN requestSent = FALSE; - - irp = WdfRequestWdmGetIrp(Request); - irpStack = IoGetCurrentIrpStackLocation(irp); - nextStack = IoGetNextIrpStackLocation(irp); - - // Set the parameters in the next stack location. - nextStack->Parameters.Scsi.Srb = irpStack->Parameters.Scsi.Srb; - nextStack->MajorFunction = IRP_MJ_SCSI; - nextStack->MinorFunction = IRP_MN_SCSI_CLASS; - - WdfRequestSetCompletionRoutine(Request, RequestDummyCompletionRoutine, NULL); - - status = RequestSend(DeviceExtension, - Request, - DeviceExtension->IoTarget, - 0, - &requestSent); - - // send the request straight down (asynchronously) - if (!requestSent) - { - // fail the request - RequestCompletion(DeviceExtension, Request, status, WdfRequestGetInformation(Request)); - } - - return; -} - - - -// -// Serial I/O Queue Event callbacks -// - -VOID -SequentialQueueEvtIoReadWrite( - _In_ WDFQUEUE Queue, - _In_ WDFREQUEST Request, - _In_ size_t Length - ) -/*++ -Routine Description: - - validate and process read/write request. - -Arguments: - - Queue - parallel queue itself - - Request - handle to the incoming WDF Request object - - Length - read / write lenght - -Return Value: - - None - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - WDFDEVICE device = WdfIoQueueGetDevice(Queue); - PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device); - WDF_REQUEST_PARAMETERS requestParameters; - PIRP wdmIrp = WdfRequestWdmGetIrp(Request); - PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(wdmIrp); - PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); - - // Get the request parameters - WDF_REQUEST_PARAMETERS_INIT(&requestParameters); - WdfRequestGetParameters(Request, &requestParameters); - - if (requestParameters.Type == WdfRequestTypeRead) - { - TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, - "Receiving READ, Length %Ix\n", (ULONG) Length)); - } - else - { - TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, - "Receiving WRITE, Length %Ix\n", (ULONG) Length)); - } - - // Check if a verify is required before a READ/WRITE - if (TEST_FLAG(deviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME) && - (requestParameters.MinorFunction != CDROM_VOLUME_VERIFY_CHECKED) && - !TEST_FLAG(currentIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)) - { - // DO_VERIFY_VOLUME is set for the device object, - // but this request is not itself a verify request. - // So fail this request. - RequestCompletion(deviceExtension, Request, STATUS_VERIFY_REQUIRED, 0); - } - else - { - // Since we've bypassed the verify-required tests we don't need to repeat - // them with this IRP - in particular we don't want to worry about - // hitting them at the partition 0 level if the request has come through - // a non-zero partition. - currentIrpStack->MinorFunction = CDROM_VOLUME_VERIFY_CHECKED; - - // Fail READ/WRITE requests when music is playing - if (deviceExtension->DeviceAdditionalData.PlayActive) - { - RequestCompletion(deviceExtension, Request, STATUS_DEVICE_BUSY, 0); - - return; - } - - // Fail READ/WRITE requests from non-owners if the drive is locked - if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request))) - { - RequestCompletion(deviceExtension, Request, STATUS_ACCESS_DENIED, 0); - - return; - } - - // Succeed READ/WRITE requests of length 0 - if (Length == 0) - { - // Several parts of the code turn 0 into 0xffffffff, - // so don't process a zero-length request any further. - RequestCompletion(deviceExtension, Request, STATUS_SUCCESS, Length); - - return; - } - - // If there is an unexpected write request, we want to rediscover MMC capabilities - if (!deviceExtension->DeviceAdditionalData.Mmc.WriteAllowed && - (requestParameters.Type == WdfRequestTypeWrite)) - { - // Schedule MMC capabilities update now, but perform it later in a work item - deviceExtension->DeviceAdditionalData.Mmc.UpdateState = CdromMmcUpdateRequired; - } - - // If MMC capabilities update is required, we create a separate work item to avoid blocking - // the current thread; otherwise, we initiate an async read/write in the current thread. - if (DeviceIsMmcUpdateRequired(deviceExtension->Device)) - { - deviceExtension->ReadWriteWorkItemContext.OriginalRequest = Request; - WdfWorkItemEnqueue(deviceExtension->ReadWriteWorkItem); - - status = STATUS_SUCCESS; - } - else - { - status = RequestValidateReadWrite(deviceExtension, Request, requestParameters); - - if (NT_SUCCESS(status)) - { - status = RequestHandleReadWrite(deviceExtension, Request, requestParameters); - } - } - - if (!NT_SUCCESS(status)) - { - RequestCompletion(deviceExtension, Request, status, 0); - } - } - - return; -} - - -VOID -ReadWriteWorkItemRoutine( - _In_ WDFWORKITEM WorkItem - ) -/*++ - -Routine Description: - - Work item routine for validating and initiating read and write requests. - The reason why we do that from a work item is because we may need to update MMC - capabilities before validating a read/write request and that is a sync operation. - -Arguments: - - WorkItem - WDF work item - -Return Value: - - none - ---*/ -{ - PCDROM_DEVICE_EXTENSION deviceExtension = NULL; - WDFREQUEST readWriteRequest = NULL; - WDF_REQUEST_PARAMETERS readWriteRequestParameters; - NTSTATUS status = STATUS_SUCCESS; - - PAGED_CODE (); - - deviceExtension = WdfObjectGetTypedContext(WdfWorkItemGetParentObject(WorkItem), CDROM_DEVICE_EXTENSION); - readWriteRequest = deviceExtension->ReadWriteWorkItemContext.OriginalRequest; - deviceExtension->ReadWriteWorkItemContext.OriginalRequest = NULL; - - WDF_REQUEST_PARAMETERS_INIT(&readWriteRequestParameters); - WdfRequestGetParameters(readWriteRequest, &readWriteRequestParameters); - - if (DeviceIsMmcUpdateRequired(deviceExtension->Device)) - { - // Issue command to update the drive capabilities. - // The failure of MMC update is not considered critical, so we'll - // continue to process the request even if MMC update fails. - (VOID) DeviceUpdateMmcCapabilities(deviceExtension->Device); - } - - // Now verify and process the request - if (NT_SUCCESS(status)) - { - status = RequestValidateReadWrite(deviceExtension, readWriteRequest, readWriteRequestParameters); - } - if (NT_SUCCESS(status)) - { - status = RequestHandleReadWrite(deviceExtension, readWriteRequest, readWriteRequestParameters); - } - - // Complete the request immediately on failure - if (!NT_SUCCESS(status)) - { - RequestCompletion(deviceExtension, readWriteRequest, status, 0); - } -} - - -VOID -SequentialQueueEvtIoDeviceControl( - _In_ WDFQUEUE Queue, - _In_ WDFREQUEST Request, - _In_ size_t OutputBufferLength, - _In_ size_t InputBufferLength, - _In_ ULONG IoControlCode - ) -/*++ -Routine Description: - - validate and process IOCTL request. - -Arguments: - - Queue - sequential queue - - Request - handle to the incoming WDF Request object - -Return Value: - - None - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - WDFDEVICE device = WdfIoQueueGetDevice(Queue); - PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(device); - PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); - PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); - WDF_REQUEST_PARAMETERS requestParameters; - - UNREFERENCED_PARAMETER(OutputBufferLength); - UNREFERENCED_PARAMETER(InputBufferLength); - UNREFERENCED_PARAMETER(IoControlCode); - - // get the request parameters - WDF_REQUEST_PARAMETERS_INIT(&requestParameters); - WdfRequestGetParameters(Request, &requestParameters); - - // If the device is in exclusive mode, check whether the request is from - // the handle that locked the device - if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request))) - { - BOOLEAN isBlocked = FALSE; - - status = RequestIsIoctlBlockedByExclusiveAccess(Request, &isBlocked); - if (NT_SUCCESS(status) && isBlocked) - { - if (requestContext->SyncRequired) - { - // set the following event, so RequestSynchronizeProcessWithSerialQueue() can contintue run to process the real request. - // this function will wait for the request process finishes. - KeSetEvent(requestContext->SyncEvent, IO_CD_ROM_INCREMENT, FALSE); - } - else - { - TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, - "DeviceEvtIoInCallerContext: Access Denied! Device in exclusive mode.Failing Ioctl %lx\n", - requestParameters.Parameters.DeviceIoControl.IoControlCode)); - RequestCompletion(deviceExtension, Request, STATUS_ACCESS_DENIED, 0); - } - - return; - } - } - - if (!cdData->Mmc.WriteAllowed && - ((requestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_IS_WRITABLE) || - (requestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_DISK_VERIFY))) - { - cdData->Mmc.UpdateState = CdromMmcUpdateRequired; - } - - // check if this is a synchronized ioctl - if (requestContext->SyncRequired) - { - // set the following event, so RequestSynchronizeProcessWithSerialQueue() can contintue run to process the real request. - // this function will wait for the request process finishes. - KeSetEvent(requestContext->SyncEvent, IO_CD_ROM_INCREMENT, FALSE); - } - else - { - deviceExtension->IoctlWorkItemContext.OriginalRequest = Request; - - // all other IOCTL processing is currently processed via a - // work item running at PASSIVE_LEVEL. - WdfWorkItemEnqueue(deviceExtension->IoctlWorkItem); - } - - return; -} - - -VOID -IoctlWorkItemRoutine( - _In_ WDFWORKITEM WorkItem - ) -/*++ - -Routine Description: - - Work item routine for processing ioctl requests. - This is needed because event callbacks are called at DISPATCH_LEVEL and ioctl - requests are currently processed synchronously and not asynchronously. - -Arguments: - - WorkItem - WDF work item - -Return Value: - - none - ---*/ -{ - PCDROM_DEVICE_EXTENSION deviceExtension = NULL; - - PAGED_CODE (); - - deviceExtension = WdfObjectGetTypedContext(WdfWorkItemGetParentObject(WorkItem), CDROM_DEVICE_EXTENSION); - - if (DeviceIsMmcUpdateRequired(deviceExtension->Device)) - { - // Issue command to update the drive capabilities. - // The failure of MMC update is not considered critical, - // so that we'll continue to process I/O even MMC update fails. - DeviceUpdateMmcCapabilities(deviceExtension->Device); - } - - RequestProcessSerializedIoctl(deviceExtension, deviceExtension->IoctlWorkItemContext.OriginalRequest); -} - - -_IRQL_requires_max_(PASSIVE_LEVEL) -NTSTATUS -RequestProcessSerializedIoctl( - _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, - _In_ WDFREQUEST Request - ) -/*++ -Routine Description: - - a dispatch routine for all functions to process IOCTLs. - -Arguments: - - DeviceExtension - device context - - Request - handle to the incoming WDF Request object - -Return Value: - - NTSTATUS - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - size_t information = 0; - WDF_REQUEST_PARAMETERS requestParameters; - BOOLEAN completeRequest = TRUE; - - PAGED_CODE (); - - // Get the Request parameters - WDF_REQUEST_PARAMETERS_INIT(&requestParameters); - WdfRequestGetParameters(Request, &requestParameters); - - NormalizeIoctl(&requestParameters); - - // process IOCTLs - switch (requestParameters.Parameters.DeviceIoControl.IoControlCode) - { - case IOCTL_CDROM_READ_TOC: - case IOCTL_CDROM_GET_LAST_SESSION: - status = RequestHandleReadTOC(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_CDROM_READ_TOC_EX: - status = RequestHandleReadTocEx(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_CDROM_GET_CONFIGURATION: - status = RequestHandleGetConfiguration(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_CDROM_RAW_READ: - status = DeviceHandleRawRead(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_DISK_GET_LENGTH_INFO: - case IOCTL_DISK_GET_DRIVE_GEOMETRY: - case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: - case IOCTL_CDROM_GET_DRIVE_GEOMETRY: - case IOCTL_CDROM_GET_DRIVE_GEOMETRY_EX: - case IOCTL_STORAGE_READ_CAPACITY: - status = RequestHandleGetDriveGeometry(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_DISK_VERIFY: - status = RequestHandleDiskVerify(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_STORAGE_CHECK_VERIFY: - // IOCTL_STORAGE_CHECK_VERIFY2 was processed including send a Test Unit Read - // with srb flag SRB_CLASS_FLAGS_LOW_PRIORITY to port driver asynchronizelly. - // The original request was completed after TUR finishes. - // As CDROM.SYS serializes IOs need accessing device, it's not a big difference from above behavior to - // just process it in serialized manner. So I put it here and treat it as same as IOCTL_STORAGE_CHECK_VERIFY. - case IOCTL_STORAGE_CHECK_VERIFY2: - status = RequestHandleCheckVerify(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_DISK_GET_DRIVE_LAYOUT: - case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: - case IOCTL_DISK_GET_PARTITION_INFO: - case IOCTL_DISK_GET_PARTITION_INFO_EX: - status = RequestHandleFakePartitionInfo(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_DISK_IS_WRITABLE: - // - // Even though this media is writable, the requester of this IOCTL really - // wants to know if thw media behaves like any other disk or not. This is - // so if FeatureDefectManagement and FeatureRandomWritable are current on - // the drive-represented by the FeatureDefectManagement validation schema - // - if (DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed && - (DeviceExtension->DeviceAdditionalData.Mmc.ValidationSchema == FeatureDefectManagement)) - { - status = STATUS_SUCCESS; - } - else - { - status = STATUS_MEDIA_WRITE_PROTECTED; - } - information = 0; - break; - - case IOCTL_CDROM_PLAY_AUDIO_MSF: - status = DeviceHandlePlayAudioMsf(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_CDROM_READ_Q_CHANNEL: - status = DeviceHandleReadQChannel(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_CDROM_PAUSE_AUDIO: - status = DeviceHandlePauseAudio(DeviceExtension, Request, &information); - break; - - case IOCTL_CDROM_RESUME_AUDIO: - status = DeviceHandleResumeAudio(DeviceExtension, Request, &information); - break; - - case IOCTL_CDROM_SEEK_AUDIO_MSF: - status = DeviceHandleSeekAudioMsf(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_CDROM_STOP_AUDIO: - status = DeviceHandleStopAudio(DeviceExtension, Request, &information); - break; - - case IOCTL_CDROM_GET_VOLUME: - case IOCTL_CDROM_SET_VOLUME: - status = DeviceHandleGetSetVolume(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_DVD_GET_REGION: - status = RequestHandleGetDvdRegion(DeviceExtension, Request, &information); - break; - - case IOCTL_DVD_READ_STRUCTURE: - status = DeviceHandleReadDvdStructure(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_DVD_END_SESSION: - status = DeviceHandleDvdEndSession(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_DVD_START_SESSION: - case IOCTL_DVD_READ_KEY: - status = DeviceHandleDvdStartSessionReadKey(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_DVD_SEND_KEY: - case IOCTL_DVD_SEND_KEY2: - status = DeviceHandleDvdSendKey(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_STORAGE_SET_READ_AHEAD: - status = DeviceHandleSetReadAhead(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_CDROM_SET_SPEED: - status = DeviceHandleSetSpeed(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE: - case IOCTL_AACS_READ_MEDIA_KEY_BLOCK: - status = DeviceHandleAacsReadMediaKeyBlock(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_AACS_START_SESSION: - status = DeviceHandleAacsStartSession(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_AACS_END_SESSION: - status = DeviceHandleAacsEndSession(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_AACS_SEND_CERTIFICATE: - status = DeviceHandleAacsSendCertificate(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_AACS_GET_CERTIFICATE: - status = DeviceHandleAacsGetCertificate(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_AACS_GET_CHALLENGE_KEY: - status = DeviceHandleAacsGetChallengeKey(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_AACS_SEND_CHALLENGE_KEY: - status = DeviceHandleSendChallengeKey(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_AACS_READ_VOLUME_ID: - status = DeviceHandleReadVolumeId(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_AACS_READ_SERIAL_NUMBER: - status = DeviceHandleAacsReadSerialNumber(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_AACS_READ_MEDIA_ID: - status = DeviceHandleAacsReadMediaId(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_AACS_READ_BINDING_NONCE: - status = DeviceHandleAacsReadBindingNonce(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_AACS_GENERATE_BINDING_NONCE: - status = DeviceHandleAacsGenerateBindingNonce(DeviceExtension, Request, requestParameters, &information); - break; - - case IOCTL_CDROM_ENABLE_STREAMING: - status = RequestHandleEnableStreaming(DeviceExtension, Request, &information); - break; - - case IOCTL_CDROM_SEND_OPC_INFORMATION: - status = RequestHandleSendOpcInformation(DeviceExtension, Request, &information); - break; - - case IOCTL_CDROM_GET_PERFORMANCE: - status = RequestHandleGetPerformance(DeviceExtension, Request, requestParameters, &information); - break; - - // This IOCTL is a fake one, used for MCN process sync-ed with serial queue. - case IOCTL_MCN_SYNC_FAKE_IOCTL: - status = RequestHandleMcnSyncFakeIoctl(DeviceExtension, &information); - break; - - case IOCTL_STORAGE_MEDIA_REMOVAL: - case IOCTL_STORAGE_EJECTION_CONTROL: - { - status = RequestHandleEjectionControl(DeviceExtension, Request, requestParameters, &information); - - break; - } - - case IOCTL_STORAGE_EJECT_MEDIA: - case IOCTL_STORAGE_LOAD_MEDIA: - case IOCTL_STORAGE_LOAD_MEDIA2: - { - status = RequestHandleLoadEjectMedia(DeviceExtension, Request, requestParameters, &information); - - break; - } - - case IOCTL_STORAGE_MCN_CONTROL: - { - status = RequestHandleMcnControl(DeviceExtension, Request, &information); - - break; - } - - case IOCTL_STORAGE_RESERVE: - case IOCTL_STORAGE_RELEASE: - { - status = RequestHandleReserveRelease(DeviceExtension, Request, requestParameters, &information); - - break; - } - - case IOCTL_STORAGE_PERSISTENT_RESERVE_IN: - case IOCTL_STORAGE_PERSISTENT_RESERVE_OUT: - { - status = RequestHandlePersistentReserve(DeviceExtension, Request, requestParameters, &information); - - break; - } - -#if (NTDDI_VERSION >= NTDDI_WIN8) - case IOCTL_DISK_ARE_VOLUMES_READY: - { - status = RequestHandleAreVolumesReady(DeviceExtension, Request, requestParameters, &information); - - completeRequest = FALSE; - - break; - } - - case IOCTL_VOLUME_ONLINE: - case IOCTL_VOLUME_POST_ONLINE: - { - status = RequestHandleVolumeOnline(DeviceExtension, Request, requestParameters, &information); - - break; - } -#endif - - default: - { - status = STATUS_ACCESS_DENIED; - break; - } - } // end of switch(ioctl) - - if (completeRequest) - { - RequestCompletion(DeviceExtension, Request, status, information); - } - - return status; -} - -VOID -SequentialQueueEvtCanceledOnQueue( - _In_ WDFQUEUE Queue, - _In_ WDFREQUEST Request - ) -/*++ -Routine Description: - - Perform cancellation when request is still in queue. - - If request is sych-ed in another thread, signal the event to let that thread be able to complete the request. - Otherwise, complete the request. - -Arguments: - - Queue - serial queue - Request - handle to the incoming WDF Request object - -Return Value: - - None - ---*/ -{ - PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); - - if (requestContext->SyncRequired) - { - KeSetEvent(requestContext->SyncEvent, IO_CD_ROM_INCREMENT, FALSE); - } - else - { - PCDROM_DEVICE_EXTENSION deviceExtension = NULL; - WDFDEVICE device = WdfIoQueueGetDevice(Queue); - - deviceExtension = DeviceGetExtension(device); - - RequestCompletion(deviceExtension, Request, STATUS_CANCELLED, 0); - - } - - return; -} - - -NTSTATUS -RequestSynchronizeProcessWithSerialQueue( - _In_ WDFDEVICE Device, - _In_ WDFREQUEST Request - ) -/*++ -Routine Description: - - This is the mechanism to sync a request process in original thread with serialize queue. - initialize a EVENT and put the request inot serialize queue; - waiting for serialize queue processes to this request and signal the EVENT; - call the request handler to process this request. - -Arguments: - - DeviceExtension - device context - - Request - handle to the incoming WDF Request object - -Return Value: - - NTSTATUS - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); - PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); - PKEVENT bufferToFree = requestContext->SyncEvent; - - if (KeGetCurrentIrql() >= DISPATCH_LEVEL) { - // cannot block at or above DISPATCH_LEVEL - TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, - "RequestSynchronousProcessWithSerialQueue called at DISPATCH_LEVEL or above")); - NT_ASSERT(FALSE); - RequestCompletion(deviceExtension, Request, STATUS_INVALID_LEVEL, 0); - return STATUS_INVALID_LEVEL; - } - - // init the synchronization event - KeInitializeEvent(requestContext->SyncEvent, NotificationEvent, FALSE); - - // do we still need to do something like this? - // SET_FLAG(nextStack->Flags, SL_OVERRIDE_VERIFY_VOLUME); - - // NOTE: this mechanism relies on that KMDF will not complete request by itself. - // Doing that will cause the syncEvent not fired thus this thread will stuck. - // This should not really happen: our EvtCanceledOnQueue callbacks should be - // called even if queues are purged for some reason. The only case when these - // callbacks are not called is when a request is owned by the driver (i.e. has - // already been passed to one of the registered handlers). In this case, it is - // our responsibility to cancel such requests properly. - status = WdfDeviceEnqueueRequest(Device, Request); - - if (!NT_SUCCESS(status)) - { - // Failed to forward request! Pretend the sync event already occured, otherwise we'll hit - // an assert in RequestEvtCleanup. - KeSetEvent(requestContext->SyncEvent, IO_CD_ROM_INCREMENT, FALSE); - RequestCompletion(deviceExtension, Request, status, WdfRequestGetInformation(Request)); - } - else - { - NTSTATUS waitStatus = STATUS_UNSUCCESSFUL; - PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); - BOOLEAN fCallSyncCallback = FALSE; - PIRP irp = WdfRequestWdmGetIrp(Request); - - // ok, now wait on the event - while (waitStatus != STATUS_SUCCESS) - { - waitStatus = KeWaitForSingleObject(requestContext->SyncEvent, Executive, KernelMode, TRUE, NULL); - if (waitStatus == STATUS_SUCCESS) // must check equality -- STATUS_ALERTED is success code - { - // do nothing - } - else if (waitStatus != STATUS_ALERTED) - { - // do nothing - TracePrint((TRACE_LEVEL_FATAL, TRACE_FLAG_IOCTL, - "Request %p on device object %p had a non-alert, non-success result from wait (%!HRESULT!)\n", - Request, Device, waitStatus)); - NT_ASSERT(FALSE); - } - else if (PsIsThreadTerminating(PsGetCurrentThread())) - { - // the thread was alerted and is terminating, so cancel the irp - // this will cause EvtIoCanceledOnQueue to be called, which will signal the event, - // so we will get out of the while loop and eventually complete the request. - if (IoCancelIrp(irp)) - { - // cancellation routine was called - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, - "Sychronize Ioctl: request %p cancelled from device %p\n", - Request, Device)); - } - else - { - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, - "Sychronize Ioctl: request %p could not be cancelled from device %p\n", - Request, Device)); - } - } - else - { - TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_IOCTL, - "SPURIOUS ALERT waiting for Request %p on device %p (%!STATUS!)\n", - Request, Device, status)); - } - } // end of wait loop on the event - - // because we've waited an unknown amount of time, should check - // the cancelled flag to immediately fail the irp as appropriate - if (WdfRequestIsCanceled(Request)) - { - // the request was cancelled, thus we should always stop - // processing here if possible. - status = STATUS_CANCELLED; - RequestCompletion(deviceExtension, Request, status, 0); - } - else if (EXCLUSIVE_MODE(cdData) && !EXCLUSIVE_OWNER(cdData, WdfRequestGetFileObject(Request))) - { - WDF_REQUEST_PARAMETERS requestParameters; - BOOLEAN isBlocked = FALSE; - - // get the request parameters - WDF_REQUEST_PARAMETERS_INIT(&requestParameters); - WdfRequestGetParameters(Request, &requestParameters); - - status = RequestIsIoctlBlockedByExclusiveAccess(Request, &isBlocked); - if (isBlocked) - { - TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_IOCTL, - "Access Denied! Device in exclusive mode.Failing Ioctl %lx\n", - requestParameters.Parameters.DeviceIoControl.IoControlCode)); - RequestCompletion(deviceExtension, Request, STATUS_ACCESS_DENIED, 0); - } - else - { - TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, - "Ioctl %lx not blocked by cdrom being in exclusive mode\n", - requestParameters.Parameters.DeviceIoControl.IoControlCode)); - fCallSyncCallback = TRUE; - } - } - else - { - fCallSyncCallback = TRUE; - } - - if (fCallSyncCallback) - { - // Synchronization completed successfully. Call the requested routine - status = requestContext->SyncCallback(Device, Request); - } - } - - // The next SequentialQueue evt routine will not be triggered until the current request is completed. - - // clean up the request context setting. - FREE_POOL(bufferToFree); - - return status; -} - -NTSTATUS -RequestIsIoctlBlockedByExclusiveAccess( - _In_ WDFREQUEST Request, - _Out_ PBOOLEAN IsBlocked - ) -/*++ -Routine Description: - - Check if the IOCTL request should be blocked or not according to - the exclusive lock stat. - -Arguments: - - Request - handle to the incoming WDF Request object - -Return Value: - - NTSTATUS - - IsBlocked - TRUE (be blocked); FALSE (not blocked) - ---*/ -{ - NTSTATUS status = STATUS_SUCCESS; - ULONG ioctlCode = 0; - ULONG baseCode = 0; - WDF_REQUEST_PARAMETERS requestParameters; - - // Get the Request parameters - WDF_REQUEST_PARAMETERS_INIT(&requestParameters); - WdfRequestGetParameters(Request, &requestParameters); - - // check and initialize parameter - if (IsBlocked == NULL) - { - //This is an internal function and this parameter must be supplied. - NT_ASSERT(FALSE); - - return STATUS_INVALID_PARAMETER; - } - else - { - *IsBlocked = FALSE; - } - - // check if this is an IOCTL - if ((requestParameters.Type == WdfRequestTypeDeviceControl) || - (requestParameters.Type == WdfRequestTypeDeviceControlInternal)) - { - // - // Allow minimum set of commands that are required for the disk manager - // to show the CD device, while in exclusive mode. - // Note: These commands should not generate any requests to the device, - // and thus must be handled directly in StartIO during exclusive - // access (except for the exclusive owner, of course). - // - ioctlCode = requestParameters.Parameters.DeviceIoControl.IoControlCode; - baseCode = DEVICE_TYPE_FROM_CTL_CODE(ioctlCode); - - if (ioctlCode == IOCTL_SCSI_GET_ADDRESS || - ioctlCode == IOCTL_STORAGE_GET_HOTPLUG_INFO || - ioctlCode == IOCTL_STORAGE_GET_DEVICE_NUMBER || - ioctlCode == IOCTL_STORAGE_GET_MEDIA_TYPES_EX || - ioctlCode == IOCTL_CDROM_EXCLUSIVE_ACCESS || - ioctlCode == IOCTL_CDROM_GET_INQUIRY_DATA - ) - { - *IsBlocked = FALSE; - } - - // - // Handle IOCTL_STORAGE_QUERY_PROPERTY special because: - // (1) PropertyExistsQuery should not generate device i/o - // (2) Queries for StorageDeviceProperty and StorageAdapterDescriptor - // will return cache'd data - else if (ioctlCode == IOCTL_STORAGE_QUERY_PROPERTY) - { - PSTORAGE_PROPERTY_QUERY query = NULL; - status = WdfRequestRetrieveInputBuffer(Request, - requestParameters.Parameters.DeviceIoControl.InputBufferLength, - (PVOID*)&query, - NULL); - - if (NT_SUCCESS(status)) - { - if (query != NULL) - { - if (query->QueryType == PropertyExistsQuery) - { - *IsBlocked = FALSE; - } - else if ((query->QueryType == PropertyStandardQuery) && - ((query->PropertyId == StorageDeviceProperty) || - (query->PropertyId == StorageAdapterProperty))) - { - *IsBlocked = FALSE; - } - } - } - } - - // Return TRUE for unknown IOCTLs with STORAGE bases - else if (baseCode == IOCTL_SCSI_BASE || - baseCode == IOCTL_DISK_BASE || - baseCode == IOCTL_CDROM_BASE || - baseCode == IOCTL_STORAGE_BASE || - baseCode == IOCTL_DVD_BASE ) - { - *IsBlocked = TRUE; - } - } - else - { - // this should only be called with an IOCTL - NT_ASSERT(FALSE); - - status = STATUS_INVALID_PARAMETER; - } - - return status; -} - -BOOLEAN -DeviceIsMmcUpdateRequired( - _In_ WDFDEVICE Device - ) -/*++ -Routine Description: - - Check if the device needs to update its MMC information. - -Arguments: - - Device - device to be checked. - -Return Value: - - TRUE (require update); FALSE (not require update) - ---*/ -{ - PCDROM_DEVICE_EXTENSION deviceExtension = DeviceGetExtension(Device); - PCDROM_DATA cdData = &(deviceExtension->DeviceAdditionalData); - - if ((cdData->Mmc.IsMmc) && - (cdData->Mmc.UpdateState == CdromMmcUpdateRequired)) - { - return TRUE; - } - else - { - // no update required: just proceed - return FALSE; - } -} - -VOID -RequestEvtCleanup( - _In_ WDFOBJECT Request - ) -/*++ -Routine Description: - - Request cleanup callback. - -Arguments: - - Request - request to clean up. - -Return Value: - - None - ---*/ -{ - WDFREQUEST request = (WDFREQUEST)Request; - PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(request); - - if (requestContext->SyncRequired) - { - // the event should have been signaled, just check that - NT_ASSERT(KeReadStateEvent(requestContext->SyncEvent) != 0); - } -} - |
