diff options
Diffstat (limited to 'storage/class/cdrom/src/zpodd.c')
| -rw-r--r-- | storage/class/cdrom/src/zpodd.c | 823 |
1 files changed, 0 insertions, 823 deletions
diff --git a/storage/class/cdrom/src/zpodd.c b/storage/class/cdrom/src/zpodd.c deleted file mode 100644 index 9e729143..00000000 --- a/storage/class/cdrom/src/zpodd.c +++ /dev/null @@ -1,823 +0,0 @@ -/*++ - -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 = ExAllocatePool2(POOL_FLAG_NON_PAGED, - sizeof(ZERO_POWER_ODD_INFO), - CDROM_TAG_ZERO_POWER_ODD); - - if (zpoddInfo == NULL) - { - status = STATUS_INSUFFICIENT_RESOURCES; - - goto Cleanup; - } - - // - // 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 - - |
