diff options
| author | Dave Wilson <[email protected]> | 2015-04-29 09:48:49 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-04-29 10:47:29 -0700 |
| commit | d40232638faaab19de557e70a3ee938da7a35295 (patch) | |
| tree | 14e61c973745949af186b7940e3a53d25322f5de /storage/class/cdrom/src/zpodd.c | |
| parent | 02e5b090a6131a7cc1b90f4a9373117c9e3c7088 (diff) | |
samples update for //build
Diffstat (limited to 'storage/class/cdrom/src/zpodd.c')
| -rw-r--r-- | storage/class/cdrom/src/zpodd.c | 825 |
1 files changed, 825 insertions, 0 deletions
diff --git a/storage/class/cdrom/src/zpodd.c b/storage/class/cdrom/src/zpodd.c new file mode 100644 index 00000000..59434896 --- /dev/null +++ b/storage/class/cdrom/src/zpodd.c @@ -0,0 +1,825 @@ +/*++ + +Copyright (C) Microsoft Corporation. All rights reserved. + +Module Name: + + zpodd.c + +Abstract: + + Code for Zero Power ODD support. + +Environment: + + kernel mode only + +Notes: + + +Revision History: + +--*/ + +#include "ntddk.h" +#include "ntddstor.h" +#include "wdmguid.h" +#include "cdrom.h" +#include "mmc.h" +#include "ioctl.h" +#include "scratch.h" + +#ifdef DEBUG_USE_WPP +#include "zpodd.tmh" +#endif + +_IRQL_requires_max_(PASSIVE_LEVEL) +ULONG +DeviceGetZPODDEnabledFromRegistry(); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceQueryD3ColdInterface( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Out_ PD3COLD_SUPPORT_INTERFACE D3ColdInterface + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceSendEnableIdlePowerIoctl( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN WakeCapable, + _In_ BOOLEAN Enable, + _In_ ULONG D3IdleTimeout + ); + +#if ALLOC_PRAGMA + +#pragma alloc_text(PAGE, DeviceInitializeZPODD) +#pragma alloc_text(PAGE, DeviceGetZPODDEnabledFromRegistry) +#pragma alloc_text(PAGE, DeviceQueryD3ColdInterface) +#pragma alloc_text(PAGE, DeviceSendEnableIdlePowerIoctl) +#pragma alloc_text(PAGE, DeviceReleaseZPODDResources) +#pragma alloc_text(PAGE, DeviceZPODDIsInHomePosition) +#pragma alloc_text(PAGE, DeviceMarkActive) + +#endif + +#pragma warning(push) +#pragma warning(disable:4152) // nonstandard extension, function/data pointer conversion in expression +#pragma warning(disable:26000) // read overflow reported because of pointer type conversion + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceInitializeZPODD( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + This routine initialize the contents of ZPODD structure. + +Arguments: + + DeviceExtension - the device extension + +Return Value: + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + NTSTATUS tempStatus = STATUS_SUCCESS; + PZERO_POWER_ODD_INFO zpoddInfo = NULL; + PFEATURE_DATA_REMOVABLE_MEDIUM removableMediumHeader = NULL; + ULONG ZPODDEnabledInRegistry = 0; + PD3COLD_SUPPORT_INTERFACE d3ColdInterface = NULL; + DEVICE_WAKE_DEPTH deepestWakeableDstate = DeviceWakeDepthNotWakeable; + BOOLEAN inHomePosition = FALSE; + + PAGED_CODE(); + + if (DeviceExtension->ZeroPowerODDInfo != NULL) + { + // + // Already initialized. + // + + goto Cleanup; + } + + ZPODDEnabledInRegistry = DeviceGetZPODDEnabledFromRegistry(); + + if (ZPODDEnabledInRegistry == 0) + { + // + // User has explicitly disabled Zero Power ODD. + // + + status = STATUS_NOT_SUPPORTED; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceInitializeZPODD: ZPODD not enabled due to registry settings.\n" + )); + + goto Cleanup; + } + + zpoddInfo = ExAllocatePoolWithTag(NonPagedPoolNx, + sizeof(ZERO_POWER_ODD_INFO), + CDROM_TAG_ZERO_POWER_ODD); + + if (zpoddInfo == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + + goto Cleanup; + } + + RtlZeroMemory(zpoddInfo, sizeof (ZERO_POWER_ODD_INFO)); + + // + // Check the system for the following prerequisites: + // + // 1. SATA: Device Attention line + // 2. SATA: Asynchronous Notification + // 3. ODD: LoChange / MediaRemoval + // 4. ACPI: Wake capable + // + // Only drawer and slot loading types have well defined behaviors in the spec, so only these two + // types are supported. + // + + // + // Check for DA & AN + // + + if ((DeviceExtension->PowerDescriptor == NULL) || + (DeviceExtension->PowerDescriptor->DeviceAttentionSupported == FALSE) || + (DeviceExtension->PowerDescriptor->AsynchronousNotificationSupported == FALSE)) + { + status = STATUS_NOT_SUPPORTED; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceInitializeZPODD: ZPODD not enabled due to SATA features not present.\n" + )); + + goto Cleanup; + } + + // + // Check for LoChange / MediaRemoval + // + + removableMediumHeader = (PFEATURE_DATA_REMOVABLE_MEDIUM) + DeviceFindFeaturePage(DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBuffer, + DeviceExtension->DeviceAdditionalData.Mmc.CapabilitiesBufferSize, + FeatureRemovableMedium); + + if ((removableMediumHeader == NULL) || + !((removableMediumHeader->LoadingMechanism == LOADING_MECHANISM_TRAY) && (removableMediumHeader->Load == 0) && // Drawer ... + (removableMediumHeader->DBML != FALSE)) && // requires LoChange/NotBusy + !((removableMediumHeader->LoadingMechanism == LOADING_MECHANISM_CADDY) && (removableMediumHeader->Load == 0) && // Slot ... + (DeviceExtension->MediaChangeDetectionInfo->Gesn.Supported != FALSE))) // requires MediaRemoval + { + status = STATUS_NOT_SUPPORTED; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceInitializeZPODD: ZPODD not enabled due to ODD features not present.\n" + )); + + goto Cleanup; + } + + zpoddInfo->LoadingMechanism = removableMediumHeader->LoadingMechanism; + zpoddInfo->Load = removableMediumHeader->Load; + + // + // Check for ACPI + // + + status = DeviceQueryD3ColdInterface(DeviceExtension, &zpoddInfo->D3ColdInterface); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceInitializeZPODD: Query D3Cold support interface failed.\n" + )); + + goto Cleanup; + } + + // + // If the platform supports Zero Power ODD, the following conditions must be met: + // + // 1. The deepest wakeable D-state for the device is D3Cold; + // 2. The platform supports D3Cold for the device. + // + + d3ColdInterface = &zpoddInfo->D3ColdInterface; + + status = d3ColdInterface->GetIdleWakeInfo(d3ColdInterface->Context, + PowerSystemWorking, + &deepestWakeableDstate); + + if (!NT_SUCCESS(status)) + { + goto Cleanup; + } + + // + // DeviceExtension->PowerDescriptor->D3ColdSupported is retrieved from lower layer. + // It has more accurate supportive information than just uses d3ColdInterface->GetD3ColdCapability + // + if ((deepestWakeableDstate != DeviceWakeDepthD3cold) || + (DeviceExtension->PowerDescriptor->D3ColdSupported == FALSE)) + { + status = STATUS_NOT_SUPPORTED; + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceInitializeZPODD: ZPODD not enabled due to ACPI support not present.\n" + )); + + goto Cleanup; + } + + // + // The system meets all requirements. Go ahead and enable ZPODD. + // + + // + // Register with the runtime power framework. + // Note that no un-registration is needed during tear-down. + // D3Cold will be enabled (success case of following call) or disabled by port driver during processing Enable Idle Power IOCTL. + // + + status = DeviceSendEnableIdlePowerIoctl(DeviceExtension, TRUE, TRUE, DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS); + + if (!NT_SUCCESS(status)) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceInitializeZPODD: ZPODD not enabled due to runtime power framework.\n" + )); + + goto Cleanup; + } + + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceInitializeZPODD: ZPODD is enabled.\n" + )); + + DeviceExtension->ZeroPowerODDInfo = zpoddInfo; + + // + // If device is not in home position, then we should take an active reference here + // to prevent it from being powered off. + // + + inHomePosition = DeviceZPODDIsInHomePosition(DeviceExtension); + + if (inHomePosition == FALSE) + { + TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_POWER, + "DeviceInitializeZPODD: not ready to power off, device marked as active\n")); + + DeviceMarkActive(DeviceExtension, TRUE, FALSE); + } + else + { + // + // cache get configuration response. + // failing is not critical, so we don't want to check for status here. + // + + if (zpoddInfo->GetConfigurationBuffer == NULL) + { + tempStatus = DeviceGetConfigurationWithAlloc(DeviceExtension->Device, + &zpoddInfo->GetConfigurationBuffer, + &zpoddInfo->GetConfigurationBufferSize, + FeatureProfileList, + SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL); + + UNREFERENCED_PARAMETER(tempStatus); // Avoid PREFAST warning. + } + } + +Cleanup: + + if (!NT_SUCCESS(status)) + { + // + // We register always even in non-ZPODD case, per request from storport. + // + + tempStatus = DeviceSendEnableIdlePowerIoctl(DeviceExtension, FALSE, FALSE, DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS); + + if (NT_SUCCESS(tempStatus)) + { + // + // Mark the device active; this reference will never be released unless the system enters a + // low power state. + // + + DeviceMarkActive(DeviceExtension, TRUE, FALSE); + } + + FREE_POOL(zpoddInfo); + } + + // + // If Zero Power ODD is not supported, we should not block the device init sequence. + // + + return STATUS_SUCCESS; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +ULONG +DeviceGetZPODDEnabledFromRegistry() +/*++ + +Routine Description: + + Get the ZeroPowerODDEnabled value from registry, which dictates if Zero Power ODD + should be enabled or not. If the value is not in registry, by default Zero + Power ODD is enabled. + +Arguments: + + None + +Return Value: + + ULONG + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDFKEY registryKey = NULL; + ULONG ZPODDEnabled = 0; + + DECLARE_CONST_UNICODE_STRING(registryValueName, L"ZeroPowerODDEnabled"); + + PAGED_CODE(); + + // + // open the Parameters key under the service key. + // + + status = WdfDriverOpenParametersRegistryKey(WdfGetDriver(), + KEY_READ, + WDF_NO_OBJECT_ATTRIBUTES, + ®istryKey); + + if (NT_SUCCESS(status)) + { + status = WdfRegistryQueryULong(registryKey, + ®istryValueName, + &ZPODDEnabled); + + WdfRegistryClose(registryKey); + } + + if (!NT_SUCCESS(status)) + { + // + // By default, Zero Power ODD is enabled + // + + ZPODDEnabled = 1; + } + + return ZPODDEnabled; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceQueryD3ColdInterface( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Out_ PD3COLD_SUPPORT_INTERFACE D3ColdInterface + ) +/*++ + +Routine Description: + + Queries ACPI for the D3Cold support interface. + +Arguments: + + DeviceExtension - the device extension + D3ColdInterface - output buffer receiving the interface + +Return Value: + + NTSTATUS + +--*/ +{ + PIRP irp = NULL; + KEVENT event; + NTSTATUS status = STATUS_SUCCESS; + PDEVICE_OBJECT targetDevice = NULL; + IO_STATUS_BLOCK ioStatus = {0}; + PIO_STACK_LOCATION irpStack = NULL; + + PAGED_CODE(); + + RtlZeroMemory(D3ColdInterface, sizeof(D3COLD_SUPPORT_INTERFACE)); + + // + // Query D3COLD support interface synchronously + // + + KeInitializeEvent(&event, NotificationEvent, FALSE); + + targetDevice = IoGetAttachedDeviceReference(DeviceExtension->DeviceObject); + + irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, + targetDevice, + NULL, + 0, + 0, + &event, + &ioStatus); + + if (irp == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + + goto Cleanup; + } + + irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + irp->IoStatus.Information = 0; + + irpStack = IoGetNextIrpStackLocation(irp); + irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE; + irpStack->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_D3COLD_SUPPORT_INTERFACE; + irpStack->Parameters.QueryInterface.Size = sizeof (D3COLD_SUPPORT_INTERFACE); + irpStack->Parameters.QueryInterface.Version = D3COLD_SUPPORT_INTERFACE_VERSION; + irpStack->Parameters.QueryInterface.Interface = (PINTERFACE) D3ColdInterface; + irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL; + + status = IoCallDriver(targetDevice, irp); + + if (status == STATUS_PENDING) + { + KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); + + status = ioStatus.Status; + } + + if (!NT_SUCCESS(status)) + { + goto Cleanup; + } + + NT_ASSERT(D3ColdInterface->SetD3ColdSupport != NULL); + NT_ASSERT(D3ColdInterface->GetIdleWakeInfo != NULL); + NT_ASSERT(D3ColdInterface->GetD3ColdCapability != NULL); + +Cleanup: + + ObDereferenceObject(targetDevice); + + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +DeviceSendEnableIdlePowerIoctl( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN WakeCapable, + _In_ BOOLEAN Enable, + _In_ ULONG D3IdleTimeout + ) +/*++ + +Routine Description: + + Enables idle power support. + +Arguments: + + DeviceExtension - the device extension + WakeCapable - whether the device is wake capable + Enable - enable / disable idle power management + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + STORAGE_IDLE_POWER idlePower = {0}; + IO_STATUS_BLOCK ioStatus = {0}; + PIRP irp = NULL; + KEVENT event; + + PAGED_CODE(); + + idlePower.Version = 1; + idlePower.Size = sizeof (STORAGE_IDLE_POWER); + idlePower.WakeCapableHint = WakeCapable; + idlePower.D3ColdSupported = Enable; + idlePower.D3IdleTimeout = D3IdleTimeout; + + KeInitializeEvent(&event, NotificationEvent, FALSE); + + irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_ENABLE_IDLE_POWER, + DeviceExtension->LowerPdo, + &idlePower, + sizeof(STORAGE_IDLE_POWER), + NULL, + 0, + FALSE, + &event, + &ioStatus); + + if (irp == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + // + // Send the synchronous request to port driver. + // + + status = IoCallDriver(DeviceExtension->LowerPdo, irp); + + if (status == STATUS_PENDING) + { + KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); + + status = ioStatus.Status; + } + } + + TracePrint((TRACE_LEVEL_INFORMATION, + TRACE_FLAG_POWER, + "DeviceSendEnableIdlePowerIoctl: Port driver returned status (%x) for FDO (%p)\n" + "\tD3ColdSupported: %u\n" + "\tD3IdleTimeout: %u (ms)", + status, + DeviceExtension->DeviceObject, + Enable, + DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS)); + + return status; +} + +_IRQL_requires_max_(APC_LEVEL) +VOID +DeviceReleaseZPODDResources( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + This routine will cleanup any resources allocated for ZPODD. + +Arguments: + + DeviceExtension - the device context + +Return Value: + None. + +--*/ +{ + PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; + + PAGED_CODE() + + if (zpoddInfo != NULL) + { + FREE_POOL(zpoddInfo->GetConfigurationBuffer); + FREE_POOL(zpoddInfo); + } + + return; +} + +NTSTATUS +DeviceZPODDGetPowerupReason( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _Out_ PSTORAGE_IDLE_POWERUP_REASON PowerupReason + ) +/*++ + +Routine Description: + + This routine queries the port driver for what caused the power up. + +Arguments: + + DeviceExtension - device extension. + PowerupReason - what caused the power up. + +Return Value: + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PIRP irp = NULL; + IO_STATUS_BLOCK ioStatus = {0}; + KEVENT event; + + RtlZeroMemory(PowerupReason, sizeof (STORAGE_IDLE_POWERUP_REASON)); + + PowerupReason->Size = sizeof (STORAGE_IDLE_POWERUP_REASON); + PowerupReason->Version = STORAGE_IDLE_POWERUP_REASON_VERSION_V1; + + // + // Setup a synchronous irp. + // + + KeInitializeEvent(&event, NotificationEvent, FALSE); + + irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_IDLE_POWERUP_REASON, + DeviceExtension->LowerPdo, + PowerupReason, + sizeof (STORAGE_IDLE_POWERUP_REASON), + PowerupReason, + sizeof (STORAGE_IDLE_POWERUP_REASON), + FALSE, + &event, + &ioStatus); + + if (irp == NULL) + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + // + // Send the synchronous request to port driver. + // + + status = IoCallDriver(DeviceExtension->LowerPdo, irp); + + if (status == STATUS_PENDING) + { + KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); + + status = ioStatus.Status; + } + } + + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +DeviceZPODDIsInHomePosition( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension + ) +/*++ + +Routine Description: + + Checks to see if the device is ready to be powered off. + Requirements are: 1. tray closed 2. no media present. + +Arguments: + + DeviceExtension - device extension. + +Return Value: + BOOLEAN + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; + SCSI_REQUEST_BLOCK srb = {0}; + PCDB cdb = (PCDB) srb.Cdb; + BOOLEAN inHomePosition = FALSE; + + PAGED_CODE(); + + if (zpoddInfo != NULL) + { + // + // Clear sense data. + // + + zpoddInfo->SenseKey = 0; + zpoddInfo->AdditionalSenseCode = 0; + zpoddInfo->AdditionalSenseCodeQualifier = 0; + + // + // Send a Test Unit Ready to check media & tray status. + // + + RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); + + srb.CdbLength = 6; + cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; + + srb.TimeOutValue = CDROM_TEST_UNIT_READY_TIMEOUT; + + status = DeviceSendSrbSynchronously(DeviceExtension->Device, + &srb, + NULL, + 0, + FALSE, + NULL); + + // + // At this time, sense data, if available, is already copied into zpoddInfo. + // + // We don't check for status because we expect it to fail in case there is no media in device. + // + // Should enter Zero Power state if: + // + // Drawer: 02/3A/01 + // Slot: 02/3A/xx + // + + if (((zpoddInfo->LoadingMechanism == LOADING_MECHANISM_TRAY) && (zpoddInfo->Load == 0) && // Drawer + (zpoddInfo->SenseKey == SCSI_SENSE_NOT_READY) && + (zpoddInfo->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE) && + (zpoddInfo->AdditionalSenseCodeQualifier == 0x01)) || + ((zpoddInfo->LoadingMechanism == LOADING_MECHANISM_CADDY) && (zpoddInfo->Load == 0) && // Slot + (zpoddInfo->SenseKey == SCSI_SENSE_NOT_READY) && + (zpoddInfo->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE))) + { + inHomePosition = TRUE; + } + } + + return inHomePosition; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +DeviceMarkActive( + _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, + _In_ BOOLEAN IsActive, + _In_ BOOLEAN SetIdleTimeout + ) +/*++ + +Routine Description: + + This routine will mark the device as active / idle. + +Arguments: + + DeviceExtension - the device context + IsActive - if the device should be marked as active + +Return Value: + None. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; + + PAGED_CODE() + + if (DeviceExtension->IsActive != IsActive) + { + if ((IsActive == FALSE) && (zpoddInfo != NULL)) + { + // cache get configuration response. + // failing is not critical, so we don't want to check for status here. + if (zpoddInfo->GetConfigurationBuffer == NULL) + { + (VOID)DeviceGetConfigurationWithAlloc(DeviceExtension->Device, + &zpoddInfo->GetConfigurationBuffer, + &zpoddInfo->GetConfigurationBufferSize, + FeatureProfileList, + SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL); + } + } + + if (SetIdleTimeout) + { + status = DeviceSendEnableIdlePowerIoctl(DeviceExtension, + FALSE, + FALSE, + IsActive ? DELAY_TIME_TO_ENTER_ZERO_POWER_IN_MS : DELAY_TIME_TO_ENTER_AOAC_IDLE_POWER_IN_MS); + } + + if (NT_SUCCESS(status)) + { + DeviceSendIoctlAsynchronously(DeviceExtension, + IsActive ? IOCTL_STORAGE_POWER_ACTIVE : IOCTL_STORAGE_POWER_IDLE, + DeviceExtension->LowerPdo); + } + + DeviceExtension->IsActive = IsActive; + } +} + +#pragma warning(pop) // un-sets any local warning changes + + |
