|
|
/*++
Copyright (C) 1997-99 Microsoft Corporation
Module Name:
fdopower.c
Abstract:
--*/
#include "ideport.h"
//POWER_STATE
NTSTATUS IdePortIssueSetPowerState ( IN PDEVICE_EXTENSION_HEADER DoExtension, IN POWER_STATE_TYPE Type, IN POWER_STATE State, IN BOOLEAN Sync ) { PIRP irp = NULL; PIO_STACK_LOCATION irpStack; NTSTATUS status; CCHAR stackSize;
SET_POWER_STATE_CONTEXT context;
if (Sync) {
KeInitializeEvent( &context.Event, NotificationEvent, FALSE ); }
stackSize = (CCHAR) (DoExtension->DeviceObject->StackSize);
irp = IoAllocateIrp( stackSize, FALSE );
if (irp == NULL) {
status = STATUS_NO_MEMORY; goto GetOut; }
irpStack = IoGetNextIrpStackLocation(irp);
irpStack->MajorFunction = IRP_MJ_POWER; irpStack->MinorFunction = IRP_MN_SET_POWER;
irpStack->Parameters.Power.SystemContext = 0; irpStack->Parameters.Power.Type = Type; irpStack->Parameters.Power.State = State;
IoSetCompletionRoutine(irp, IdePortPowerCompletionRoutine, Sync ? &context : NULL, TRUE, TRUE, TRUE);
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
status = PoCallDriver( DoExtension->DeviceObject, irp );
//
// Wait for the completion routine. It will be called anyway
//
//if ((status == STATUS_PENDING) && (Sync)) {
if (Sync) {
KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE, NULL);
status = context.Status; }
GetOut:
return status; }
NTSTATUS IdePortPowerCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { PSET_POWER_STATE_CONTEXT context = Context;
if (context) {
context->Status = Irp->IoStatus.Status;
KeSetEvent( &context->Event, EVENT_INCREMENT, FALSE ); }
IoFreeIrp (Irp); return STATUS_MORE_PROCESSING_REQUIRED; }
NTSTATUS IdePortSetFdoPowerState ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PFDO_EXTENSION fdoExtension; PIO_STACK_LOCATION irpStack; NTSTATUS status = STATUS_SUCCESS; PFDO_POWER_CONTEXT context; BOOLEAN powerStateChange; BOOLEAN systemPowerContext = FALSE; BOOLEAN devicePowerContext = FALSE;
DebugPrint ((DBG_POWER, "FDO devobj 0x%x got power irp 0x%x\n", DeviceObject, Irp ));
fdoExtension = DeviceObject->DeviceExtension; irpStack = IoGetCurrentIrpStackLocation (Irp);
//context = ExAllocatePool (NonPagedPool, sizeof(FDO_POWER_CONTEXT));
//
// We need two pre-alloced context structures. This is because a system power irp
// would result in a device power irp to be issued before the former is completed.
//
if (irpStack->Parameters.Power.Type == SystemPowerState) {
ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[0]), 1, 0) == 0); context = &(fdoExtension->FdoPowerContext[0]); systemPowerContext = TRUE;
} else {
ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[1]), 1, 0) == 0); context = &(fdoExtension->FdoPowerContext[1]); devicePowerContext = TRUE;
}
if (context == NULL) {
ASSERT(context); status = STATUS_NO_MEMORY; } else {
RtlZeroMemory (context, sizeof(FDO_POWER_CONTEXT));
powerStateChange = TRUE;
context->OriginalPowerIrp = Irp; context->newPowerType = irpStack->Parameters.Power.Type; context->newPowerState = irpStack->Parameters.Power.State; if (irpStack->Parameters.Power.Type == SystemPowerState) {
if (fdoExtension->SystemPowerState != irpStack->Parameters.Power.State.SystemState) {
#if DBG
ASSERT (fdoExtension->PendingSystemPowerIrp == NULL); fdoExtension->PendingSystemPowerIrp = Irp; ASSERT (fdoExtension->PendingSystemPowerIrp); #endif
if (fdoExtension->SystemPowerState == PowerSystemWorking) { POWER_STATE powerState;
//
// Getting out of working state.
//
if ((irpStack->Parameters.Power.State.SystemState == PowerSystemShutdown) && (irpStack->Parameters.Power.ShutdownType == PowerActionShutdownReset)) {
//
// spin up for BIOS POST
//
powerState.DeviceState = PowerDeviceD0;
} else { //
// power down for sleep
//
powerState.DeviceState = PowerDeviceD3; }
IoMarkIrpPending(Irp);
PoRequestPowerIrp ( fdoExtension->DeviceObject, IRP_MN_SET_POWER, powerState, FdoContingentPowerCompletionRoutine, context, NULL );
return STATUS_PENDING; }
} else {
//
// We are already in the given state
//
powerStateChange = FALSE; }
} else if (irpStack->Parameters.Power.Type == DevicePowerState) { if (fdoExtension->DevicePowerState != irpStack->Parameters.Power.State.DeviceState) { DebugPrint (( DBG_POWER, "IdePort: New Fdo 0x%x device power state 0x%x\n", fdoExtension->IdeResource.TranslatedCommandBaseAddress, irpStack->Parameters.Power.State.DeviceState )); ASSERT (fdoExtension->PendingDevicePowerIrp == NULL); #if DBG
fdoExtension->PendingDevicePowerIrp = Irp; ASSERT (fdoExtension->PendingDevicePowerIrp); #endif //DBG
if (fdoExtension->DevicePowerState == PowerDeviceD0) { //
// getting out of D0 state, better call PoSetPowerState now
//
PoSetPowerState ( DeviceObject, DevicePowerState, irpStack->Parameters.Power.State ); } } else {
//
// We are already in the given state
//
powerStateChange = FALSE; } } else { ASSERT (FALSE); status = STATUS_NOT_IMPLEMENTED; } }
if (NT_SUCCESS(status)) { IoMarkIrpPending(Irp);
IoCopyCurrentIrpStackLocationToNext (Irp);
if (powerStateChange) { IoSetCompletionRoutine(Irp, FdoPowerCompletionRoutine, context, TRUE, TRUE, TRUE); } else {
if (systemPowerContext) { ASSERT(devicePowerContext == FALSE); ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[0]), 0, 1) == 1); }
if (devicePowerContext) { ASSERT(systemPowerContext == FALSE); ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[1]), 0, 1) == 1); } //ExFreePool (context);
PoStartNextPowerIrp (Irp);
} PoCallDriver (fdoExtension->AttacheeDeviceObject, Irp); return STATUS_PENDING;
} else {
Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status;
if (context) { if (systemPowerContext) { ASSERT(devicePowerContext == FALSE); ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[0]), 0, 1) == 1); }
if (devicePowerContext) { ASSERT(systemPowerContext == FALSE); ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[1]), 0, 1) == 1); } //ExFreePool (context);
}
PoStartNextPowerIrp (Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } }
NTSTATUS FdoContingentPowerCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus ) { PFDO_POWER_CONTEXT context = Context; PFDO_EXTENSION fdoExtension; PIRP irp;
irp = context->OriginalPowerIrp; fdoExtension = DeviceObject->DeviceExtension;
if (NT_SUCCESS(IoStatus->Status)) {
IoCopyCurrentIrpStackLocationToNext (irp); IoSetCompletionRoutine(irp, FdoPowerCompletionRoutine, context, TRUE, TRUE, TRUE); PoCallDriver (fdoExtension->AttacheeDeviceObject, irp);
} else {
irp->IoStatus.Information = 0; irp->IoStatus.Status = IoStatus->Status;
//
// This should happen only for system power irps
//
ASSERT(context->newPowerType == SystemPowerState); ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[0]), 0, 1) == 1); //ExFreePool (context);
PoStartNextPowerIrp (irp); IoCompleteRequest(irp, IO_NO_INCREMENT); }
return IoStatus->Status; }
NTSTATUS FdoPowerCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { PFDO_POWER_CONTEXT context = Context; BOOLEAN callPoSetPowerState; PFDO_EXTENSION fdoExtension; POWER_STATE newPowerState; POWER_STATE_TYPE newPowerType; BOOLEAN unlocked = FALSE; BOOLEAN moreProcessingRequired = FALSE; NTSTATUS status;
fdoExtension = DeviceObject->DeviceExtension;
newPowerType = context->newPowerType; newPowerState = context->newPowerState;
if ((NT_SUCCESS(Irp->IoStatus.Status))) {
callPoSetPowerState = TRUE;
if (context->newPowerType == SystemPowerState) {
fdoExtension->SystemPowerState = context->newPowerState.SystemState;
if (fdoExtension->SystemPowerState == PowerSystemWorking) { POWER_STATE powerState;
//
// I don't need the context any more
//
ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[0]), 0, 1) == 1); unlocked = TRUE; moreProcessingRequired = TRUE;
ASSERT(fdoExtension->PendingSystemPowerIrp == Irp);
//
// initiate a D0 here to cause a re-enumuration
//
powerState.DeviceState = PowerDeviceD0; status = PoRequestPowerIrp ( fdoExtension->DeviceObject, IRP_MN_SET_POWER, powerState, FdoSystemPowerUpCompletionRoutine, Irp, NULL );
ASSERT(status == STATUS_PENDING); }
DebugPrint (( DBG_POWER, "IdePort: New Fdo 0x%x system power state 0x%x\n", fdoExtension->IdeResource.TranslatedCommandBaseAddress, fdoExtension->SystemPowerState));
#if DBG
if (moreProcessingRequired == FALSE) { fdoExtension->PendingSystemPowerIrp = NULL; } #endif
} else if (context->newPowerType == DevicePowerState) {
if (context->newPowerState.DeviceState == PowerDeviceD0) {
if (fdoExtension->panasonicController) {
//
// this will loop 20000 * 100 us (2000ms) the most.
//
ULONG i = 20000; while (i) { //
// the panasonic controller needs a special way to kick start
//
WRITE_PORT_UCHAR (fdoExtension->HwDeviceExtension->BaseIoAddress1.RegistersBaseAddress + 0x207, 0x81); WRITE_PORT_UCHAR (fdoExtension->HwDeviceExtension->BaseIoAddress1.RegistersBaseAddress, 0xa0); WRITE_PORT_UCHAR (fdoExtension->HwDeviceExtension->BaseIoAddress1.DriveSelect, 0xa0); if (0xa0 == READ_PORT_UCHAR (fdoExtension->HwDeviceExtension->BaseIoAddress1.DriveSelect)) { DebugPrint ((0, "panasonicController wait start count = %u\n", i)); //
// done
//
i = 0; } else { KeStallExecutionProcessor(100); i--; } } } }
if ((context->newPowerState.DeviceState == PowerDeviceD0) && (!context->TimingRestored)) {
NTSTATUS status;
status = ChannelRestoreTiming ( fdoExtension, ChannelRestoreTimingCompletionRoutine, context );
if (!NT_SUCCESS(status)) {
ChannelRestoreTimingCompletionRoutine( fdoExtension->DeviceObject, status, context ); }
return STATUS_MORE_PROCESSING_REQUIRED; }
ASSERT (fdoExtension->PendingDevicePowerIrp == Irp); fdoExtension->PendingDevicePowerIrp = NULL;
if (fdoExtension->DevicePowerState == PowerDeviceD0) {
//
// PoSetPowerState is called before we get out of D0
//
callPoSetPowerState = FALSE; }
fdoExtension->DevicePowerState = context->newPowerState.DeviceState;
if ((fdoExtension->DevicePowerState == PowerDeviceD0) && (fdoExtension->FdoState & FDOS_STARTED)) {
IoInvalidateDeviceRelations ( fdoExtension->AttacheePdo, BusRelations ); } }
if (callPoSetPowerState) {
PoSetPowerState ( DeviceObject, newPowerType, newPowerState ); }
} else {
DebugPrint ((DBG_ALWAYS, "ATAPI: devobj 0x%x failed power irp 0x%x\n", fdoExtension->AttacheeDeviceObject, Irp));
if (context->newPowerType == SystemPowerState) {
ASSERT (fdoExtension->PendingSystemPowerIrp == Irp); fdoExtension->PendingSystemPowerIrp = NULL;
} else if (context->newPowerType == DevicePowerState) {
ASSERT (fdoExtension->PendingDevicePowerIrp == Irp); fdoExtension->PendingDevicePowerIrp = NULL; }
}
//
// Done with context
//
if (!unlocked) { if (context->newPowerType == SystemPowerState) { ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[0]), 0, 1) == 1); } else { ASSERT(InterlockedCompareExchange(&(fdoExtension->PowerContextLock[1]), 0, 1) == 1); } } //ExFreePool (Context);
//
// wait for the device irp to complete
//
if (moreProcessingRequired) { return STATUS_MORE_PROCESSING_REQUIRED; }
//
// If pending has be returned for this irp then mark the current stack as
// pending.
//
//if (Irp->PendingReturned) {
// IoMarkIrpPending(Irp);
//}
PoStartNextPowerIrp (Irp);
return Irp->IoStatus.Status; }
VOID FdoChildReportPowerDown ( IN PFDO_EXTENSION FdoExtension, IN PPDO_EXTENSION PdoExtension ) { KIRQL currentIrql; POWER_STATE powerState;
KeAcquireSpinLock(&FdoExtension->LogicalUnitListSpinLock, ¤tIrql);
FdoExtension->NumberOfLogicalUnitsPowerUp--;
if (FdoExtension->NumberOfLogicalUnitsPowerUp == 0) {
DebugPrint ((DBG_POWER, "FdoChildReportPowerDown: sleep fdo 0x%x\n", FdoExtension));
//
// All the children are powered down, we can now power down
// the parent (the controller)
//
powerState.DeviceState = PowerDeviceD3; PoRequestPowerIrp ( FdoExtension->DeviceObject, IRP_MN_SET_POWER, powerState, NULL, NULL, NULL );
} else if (FdoExtension->NumberOfLogicalUnitsPowerUp < 0) {
//
// should never happen. If it did, pretend it didn't
//
ASSERT (FALSE); FdoExtension->NumberOfLogicalUnitsPowerUp = 0; }
KeReleaseSpinLock(&FdoExtension->LogicalUnitListSpinLock, currentIrql);
return; }
NTSTATUS FdoChildRequestPowerUp ( IN PFDO_EXTENSION FdoExtension, IN PPDO_EXTENSION PdoExtension, IN PVOID Context ) { KIRQL currentIrql; NTSTATUS status; POWER_STATE powerState;
KeAcquireSpinLock(&FdoExtension->LogicalUnitListSpinLock, ¤tIrql);
status = STATUS_SUCCESS;
if (FdoExtension->NumberOfLogicalUnitsPowerUp == 0) {
DebugPrint ((DBG_POWER, "FdoChildRequestPowerUp: wake up fdo 0x%x\n", FdoExtension));
KeReleaseSpinLock(&FdoExtension->LogicalUnitListSpinLock, currentIrql);
//
// One of the children is coming out of sleep,
// we need to power up the parent (the controller)
//
powerState.DeviceState = PowerDeviceD0; status = PoRequestPowerIrp ( FdoExtension->DeviceObject, IRP_MN_SET_POWER, powerState, FdoChildRequestPowerUpCompletionRoutine, Context, NULL ); ASSERT (NT_SUCCESS(status)); status = STATUS_PENDING;
} else {
FdoExtension->NumberOfLogicalUnitsPowerUp++;
if (FdoExtension->NumberOfLogicalUnitsPowerUp > FdoExtension->NumberOfLogicalUnits) {
//
// should never happen. If it did, pretend it didn't
//
ASSERT (FALSE); FdoExtension->NumberOfLogicalUnitsPowerUp = FdoExtension->NumberOfLogicalUnits; }
KeReleaseSpinLock(&FdoExtension->LogicalUnitListSpinLock, currentIrql);
PdoRequestParentPowerUpCompletionRoutine ( Context, STATUS_SUCCESS ); }
return status; }
NTSTATUS FdoChildRequestPowerUpCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus ) { PFDO_EXTENSION fdoExtension;
fdoExtension = DeviceObject->DeviceExtension;
if (NT_SUCCESS(IoStatus->Status)) {
KIRQL currentIrql; KeAcquireSpinLock(&fdoExtension->LogicalUnitListSpinLock, ¤tIrql);
fdoExtension->NumberOfLogicalUnitsPowerUp++;
KeReleaseSpinLock(&fdoExtension->LogicalUnitListSpinLock, currentIrql); }
PdoRequestParentPowerUpCompletionRoutine ( Context, IoStatus->Status );
return IoStatus->Status; }
NTSTATUS ChannelQueryPowerState ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) { PIO_STACK_LOCATION irpStack; PFDO_EXTENSION fdoExtension;
fdoExtension = DeviceObject->DeviceExtension;
#if defined (DONT_POWER_DOWN_PAGING_DEVICE)
irpStack = IoGetCurrentIrpStackLocation (Irp);
if (!fdoExtension->CrashDumpPathCount || ((irpStack->Parameters.Power.Type == SystemPowerState) && (irpStack->Parameters.Power.State.SystemState == PowerSystemWorking)) || ((irpStack->Parameters.Power.Type == DevicePowerState) && (irpStack->Parameters.Power.State.SystemState == PowerDeviceD0))) {
Irp->IoStatus.Status = STATUS_SUCCESS;
} else {
Irp->IoStatus.Status = STATUS_DEVICE_POWER_FAILURE; } #else
Irp->IoStatus.Status = STATUS_SUCCESS;
#endif // DONT_POWER_DOWN_PAGING_DEVICE
IoCopyCurrentIrpStackLocationToNext (Irp); PoStartNextPowerIrp (Irp); return PoCallDriver (fdoExtension->AttacheeDeviceObject, Irp); }
NTSTATUS FdoSystemPowerUpCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus ) { PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension; PIRP irp = Context;
#if DBG
fdoExtension->PendingSystemPowerIrp = NULL; #endif
//
// start the next system power irp
//
PoStartNextPowerIrp (irp);
if (!NT_SUCCESS(IoStatus->Status)) { irp->IoStatus.Status = IoStatus->Status; }
IoCompleteRequest(irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
|