|
|
/*++
Copyright (c) 1990-2000 Microsoft Corporation
Module Name:
power.c
Abstract:
This file contains the support for power management
Environment:
Kernel Mode Driver.
Notes:
Nothing in here or in routines referenced from here should be pageable.
Revision History:
--*/
#include "busp.h"
#include "pnpisa.h"
#include <initguid.h>
#include <wdmguid.h>
#include "halpnpp.h"
NTSTATUS PiDispatchPower( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp );
NTSTATUS PiDispatchPowerFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp );
NTSTATUS PiDispatchPowerPdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp );
NTSTATUS PipPassPowerIrpFdo( PDEVICE_OBJECT DeviceObject, PIRP Irp );
NTSTATUS PipPowerIrpNotSupportedPdo( PDEVICE_OBJECT DeviceObject, PIRP Irp );
NTSTATUS PipQueryPowerStatePdo ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp );
NTSTATUS PipSetPowerStatePdo ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp );
NTSTATUS PipSetQueryPowerStateFdo ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp );
NTSTATUS PipRequestPowerUpCompletionRoutinePdo ( IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus );
NTSTATUS FdoContingentPowerCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus );
const PUCHAR SystemPowerStateStrings[] = { "Unspecified", "Working", "Sleeping1", "Sleeping2", "Sleeping3", "Hibernate", "Shutdown" };
const PUCHAR DevicePowerStateStrings[] = { "Unspecified", "D0", "D1", "D2", "D3" };
const PPI_DISPATCH PiPowerDispatchTableFdo[] = { PipPassPowerIrpFdo, PipPassPowerIrpFdo, PipSetQueryPowerStateFdo, PipSetQueryPowerStateFdo, };
#if ISOLATE_CARDS
const PPI_DISPATCH PiPowerDispatchTablePdo[] = { PipPowerIrpNotSupportedPdo, PipPowerIrpNotSupportedPdo, PipSetPowerStatePdo, PipQueryPowerStatePdo, }; #endif
VOID PipDumpPowerIrpLocation( PIO_STACK_LOCATION IrpSp ) { DebugPrintContinue(( DEBUG_POWER, "%s %d\n", (IrpSp->Parameters.Power.Type == DevicePowerState) ? DevicePowerStateStrings[IrpSp->Parameters.Power.State.DeviceState] : SystemPowerStateStrings[IrpSp->Parameters.Power.State.SystemState], IrpSp->Parameters.Power.ShutdownType)); }
NTSTATUS PiDispatchPower( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp )
/*++
Routine Description:
This routine handles all the IRP_MJ_POWER IRPs.
Arguments:
DeviceObject - Pointer to the device object for which this IRP applies.
Irp - Pointer to the IRP_MJ_PNP_POWER IRP to dispatch.
Return Value:
NT status.
--*/ { PIO_STACK_LOCATION irpSp; NTSTATUS status = STATUS_SUCCESS; PPI_BUS_EXTENSION busExtension;
//
// Make sure this is a valid device object.
//
busExtension = DeviceObject->DeviceExtension;
#if !ISOLATE_CARDS
return PiDispatchPowerFdo(DeviceObject, Irp); #else
if (busExtension->Flags & DF_BUS) { return PiDispatchPowerFdo(DeviceObject, Irp); } else { return PiDispatchPowerPdo(DeviceObject, Irp); } #endif
}
#if ISOLATE_CARDS
NTSTATUS PipPowerIrpNotSupportedPdo( PDEVICE_OBJECT DeviceObject, PIRP Irp ) { PIO_STACK_LOCATION irpSp;
irpSp = IoGetCurrentIrpStackLocation(Irp); PoStartNextPowerIrp(Irp);
DebugPrint((DEBUG_POWER, "Completing unsupported power irp %x for PDO %x\n", irpSp->MinorFunction, DeviceObject ));
PipCompleteRequest(Irp, STATUS_NOT_SUPPORTED, NULL); return STATUS_NOT_SUPPORTED; }
NTSTATUS PiDispatchPowerPdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp )
/*++
Routine Description:
This routine handles all the IRP_MJ_POWER IRPs.
Arguments:
DeviceObject - Pointer to the device object for which this IRP applies.
Irp - Pointer to the IRP_MJ_PNP_POWER IRP to dispatch.
Return Value:
NT status.
--*/ { PIO_STACK_LOCATION irpSp; NTSTATUS status = STATUS_SUCCESS; PDEVICE_INFORMATION deviceExtension;
//
// Make sure this is a valid device object.
//
deviceExtension = DeviceObject->DeviceExtension; if (deviceExtension->Flags & DF_DELETED) { status = STATUS_NO_SUCH_DEVICE; PoStartNextPowerIrp(Irp); PipCompleteRequest(Irp, status, NULL); return status; }
//
// Get a pointer to our stack location and take appropriate action based
// on the minor function.
//
irpSp = IoGetCurrentIrpStackLocation(Irp); if (irpSp->MinorFunction > IRP_MN_PO_MAXIMUM_FUNCTION) { status = PipPowerIrpNotSupportedPdo(DeviceObject, Irp); } else { status = PiPowerDispatchTablePdo[irpSp->MinorFunction](DeviceObject, Irp); } return status; }
NTSTATUS PipQueryPowerStatePdo ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) /*++
Routine Description:
This routine handles the Query_Power irp for the PDO .
Arguments:
DeviceObject - Pointer to the device object for which this IRP applies.
Irp - Pointer to the IRP_MJ_PNP_POWER IRP to dispatch.
Return Value:
NT status.
--*/ {
DEVICE_POWER_STATE targetState; NTSTATUS status; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
DebugPrint((DEBUG_POWER, "QueryPower on PDO %x: ", DeviceObject)); PipDumpPowerIrpLocation(irpSp);
if (irpSp->Parameters.Power.Type == DevicePowerState) { targetState=irpSp->Parameters.Power.State.DeviceState; ASSERT ((targetState == PowerDeviceD0) || (targetState == PowerDeviceD3));
if ((targetState == PowerDeviceD0) || (targetState == PowerDeviceD3) ) {
status=Irp->IoStatus.Status = STATUS_SUCCESS; } else { status=Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; } } else { //
// Just succeed S irps
//
status=Irp->IoStatus.Status = STATUS_SUCCESS; }
PoStartNextPowerIrp (Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT);
DebugPrint((DEBUG_POWER, "QueryPower on PDO %x: returned %x\n", DeviceObject, status)); return status;
}
NTSTATUS PipSetPowerStatePdo ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp )
/*++
Routine Description:
This routine handles SET_POWER_IRP for the IsaPnp device (i.e. PDO) It sets the devices power state to the power state type as indicated. In the case of a device state change which is transitioning a device out of the PowerDevice0 state, we need call PoSetPowerState prior to leaving the PowerDeviceD0. In the case if a device state change which is transitioning a device into the PowerDeviceD0 state, we call PoSetPowerState after the device is successfully put into the PowerDeviceD0 state.
Arguments:
DeviceObject - Pointer to the device object for which this IRP applies.
Irp - Pointer to the IRP_MJ_PNP_POWER IRP to dispatch.
Return Value:
NT status.
--*/ { PDEVICE_INFORMATION pdoExtension; NTSTATUS status; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp); DEVICE_POWER_STATE targetState=irpSp->Parameters.Power.State.DeviceState; POWER_STATE newState;
DebugPrint((DEBUG_POWER, "SetPower on PDO %x: ", DeviceObject)); PipDumpPowerIrpLocation(irpSp);
pdoExtension = PipReferenceDeviceInformation(DeviceObject, FALSE); if (pdoExtension == NULL) { status = STATUS_NO_SUCH_DEVICE; } else if (pdoExtension->Flags & DF_NOT_FUNCTIONING) { status = STATUS_NO_SUCH_DEVICE; PipDereferenceDeviceInformation(pdoExtension, FALSE); } else { if (irpSp->Parameters.Power.Type == DevicePowerState) {
// * On transition from D0 to D0, we do nothing.
//
// * On transition to D3, we'll deactivate the card.
//
// * On transition from D3->D0 we'll refresh the resources
// and activate the card.
//
if ((targetState == PowerDeviceD0) && (pdoExtension->DevicePowerState == PowerDeviceD0)) { // Do not try to power device back up if this is a D0->D0
// transition. The device is already powered.
DebugPrint((DEBUG_POWER, "PDO %x D0 -> D0 Transition ignored\n", DeviceObject)); } else if ((pdoExtension->DevicePowerState == PowerDeviceD0) && pdoExtension->CrashDump) { DebugPrint((DEBUG_POWER, "PDO %x D0 -> ?? Transition ignored, crash file\n", DeviceObject)); } else if (targetState > PowerDeviceD0) { targetState = PowerDeviceD3; DebugPrint((DEBUG_POWER, "Powering down PDO %x CSN %d/LDN %d\n", DeviceObject, pdoExtension->CardInformation->CardSelectNumber, pdoExtension->LogicalDeviceNumber )); if ((pdoExtension->Flags & (DF_ACTIVATED | DF_READ_DATA_PORT)) == DF_ACTIVATED) { if (!(PipRDPNode->Flags & (DF_STOPPED|DF_REMOVED|DF_SURPRISE_REMOVED))) { PipWakeAndSelectDevice( (UCHAR) pdoExtension->CardInformation->CardSelectNumber, (UCHAR) pdoExtension->LogicalDeviceNumber); PipDeactivateDevice(); PipWaitForKey(); } else { targetState = PowerDeviceD0; } } } else { if ((pdoExtension->Flags & (DF_ACTIVATED | DF_READ_DATA_PORT)) == DF_ACTIVATED) { DebugPrint((DEBUG_POWER, "Powering up PDO %x CSN %d/LDN %d\n", DeviceObject, pdoExtension->CardInformation->CardSelectNumber, pdoExtension->LogicalDeviceNumber )); if (!(PipRDPNode->Flags & (DF_STOPPED|DF_REMOVED|DF_SURPRISE_REMOVED))) { PipWakeAndSelectDevice( (UCHAR) pdoExtension->CardInformation->CardSelectNumber, (UCHAR) pdoExtension->LogicalDeviceNumber); status = PipSetDeviceResources( pdoExtension, pdoExtension->AllocatedResources); if (NT_SUCCESS(status)) { PipActivateDevice(); } PipWaitForKey(); } else { targetState = PowerDeviceD3; }
} } newState.DeviceState = targetState; PoSetPowerState(DeviceObject, DevicePowerState, newState); pdoExtension->DevicePowerState = targetState; } status = STATUS_SUCCESS; PipDereferenceDeviceInformation(pdoExtension, FALSE); }
Irp->IoStatus.Status = status;
PoStartNextPowerIrp (Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT);
DebugPrint((DEBUG_POWER, "SetPower on PDO %x: returned %x\n", DeviceObject, status)); return status; } #endif
NTSTATUS PipPassPowerIrpFdo( PDEVICE_OBJECT DeviceObject, PIRP Irp )
/*++
Description:
This function pass the power Irp to lower level driver.
Arguments:
DeviceObject - the Fdo Irp - the request
Return:
STATUS_PENDING
--*/ { NTSTATUS status; PPI_BUS_EXTENSION busExtension; PIO_STACK_LOCATION irpSp;
PoStartNextPowerIrp(Irp);
irpSp = IoGetCurrentIrpStackLocation(Irp); busExtension = (PPI_BUS_EXTENSION) DeviceObject->DeviceExtension;
DebugPrint((DEBUG_POWER, "Passing down power irp %x for FDO %x to %x\n", irpSp->MinorFunction, DeviceObject, busExtension->AttachedDevice ));
IoSkipCurrentIrpStackLocation(Irp); status = PoCallDriver(busExtension->AttachedDevice, Irp); DebugPrint((DEBUG_POWER, "Passed down power irp for FDO: returned %x\n", status)); return status; }
NTSTATUS PiDispatchPowerFdo( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp )
/*++
Routine Description:
This routine handles all the IRP_MJ_POWER IRPs.
Arguments:
DeviceObject - Pointer to the device object for which this IRP applies.
Irp - Pointer to the IRP_MJ_PNP_POWER IRP to dispatch.
Return Value:
NT status.
--*/ { PIO_STACK_LOCATION irpSp; NTSTATUS status = STATUS_SUCCESS; PPI_BUS_EXTENSION busExtension;
//
// Make sure this is a valid device object.
//
busExtension = DeviceObject->DeviceExtension; if (busExtension->AttachedDevice == NULL) { status = STATUS_NO_SUCH_DEVICE; PoStartNextPowerIrp(Irp); PipCompleteRequest(Irp, status, NULL); return status; }
//
// Get a pointer to our stack location and take appropriate action based
// on the minor function.
//
irpSp = IoGetCurrentIrpStackLocation(Irp); if (irpSp->MinorFunction > IRP_MN_PO_MAXIMUM_FUNCTION) { return PipPassPowerIrpFdo(DeviceObject, Irp); } else { status = PiPowerDispatchTableFdo[irpSp->MinorFunction](DeviceObject, Irp); } return status; }
NTSTATUS PipSetQueryPowerStateFdo ( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp )
/*++
Routine Description:
This routine handles QUERY_POWER or SET_POWER IRPs for the IsaPnp bus device (i.e. FDO). It sets the devices power state for the power state type as indicated. In the case of a device state change which is transitioning a device out of the PowerDevice0 state, we need call PoSetPowerState prior to leaving the PowerDeviceD0. In the case if a device state change which is transitioning a device into the PowerDeviceD0 state, we call PoSetPowerState after the device is successfully put into the PowerDeviceD0 state.
Arguments:
DeviceObject - Pointer to the device object for which this IRP applies.
Irp - Pointer to the IRP_MJ_PNP_POWER IRP to dispatch.
Return Value:
NT status.
--*/ { PPI_BUS_EXTENSION fdoExtension; PIO_STACK_LOCATION irpSp; NTSTATUS status;
fdoExtension = DeviceObject->DeviceExtension;
irpSp = IoGetCurrentIrpStackLocation (Irp);
DebugPrint((DEBUG_POWER, "%s on FDO %x: ", (irpSp->MinorFunction == IRP_MN_SET_POWER) ? "SetPower" : "QueryPower", DeviceObject)); PipDumpPowerIrpLocation(irpSp);
if (irpSp->Parameters.Power.Type == SystemPowerState) { POWER_STATE powerState;
switch (irpSp->Parameters.Power.State.SystemState) { case PowerSystemWorking:
//
// Make sure the bus is on for these system states
//
powerState.DeviceState = PowerDeviceD0; break;
case PowerSystemSleeping1: case PowerSystemHibernate: case PowerSystemShutdown: case PowerSystemSleeping2: case PowerSystemSleeping3:
//
// Going to sleep ... Power down
//
powerState.DeviceState = PowerDeviceD3; break;
default:
//
// Unknown request - be safe power up
//
ASSERT (TRUE == FALSE); powerState.DeviceState = PowerDeviceD0; break; }
DebugPrint((DEBUG_POWER, "request power irp to busdev %x, pending\n", fdoExtension->FunctionalBusDevice)); IoMarkIrpPending(Irp); PoRequestPowerIrp ( fdoExtension->FunctionalBusDevice, irpSp->MinorFunction, powerState, FdoContingentPowerCompletionRoutine, Irp, NULL );
return STATUS_PENDING;
}
status = PipPassPowerIrpFdo(DeviceObject, Irp); DebugPrint((DEBUG_POWER, "SetPower(device) on FDO %x: returned %x\n", DeviceObject, status)); return status; }
NTSTATUS FdoContingentPowerCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus ) { PIRP irp = Context; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp);
DebugPrint((DEBUG_POWER, "requested power irp completed to %x\n", DeviceObject));
//
// Propagate the status of the transient power IRP
//
irp->IoStatus.Status = IoStatus->Status;
if (NT_SUCCESS(IoStatus->Status)) {
PPI_BUS_EXTENSION fdoExtension;
fdoExtension = DeviceObject->DeviceExtension;
PoStartNextPowerIrp (irp); //
// changing device power state call PoSetPowerState now.
//
if (MinorFunction == IRP_MN_SET_POWER) { SYSTEM_POWER_STATE OldSystemPowerState = fdoExtension->SystemPowerState;
fdoExtension->SystemPowerState = irpSp->Parameters.Power.State.SystemState; fdoExtension->DevicePowerState = PowerState.DeviceState; PoSetPowerState ( DeviceObject, DevicePowerState, PowerState ); DebugPrint((DEBUG_POWER, "New FDO %x powerstate system %s/%s\n", DeviceObject, SystemPowerStateStrings[fdoExtension->SystemPowerState], DevicePowerStateStrings[fdoExtension->DevicePowerState])); #if ISOLATE_CARDS
if ((OldSystemPowerState == PowerSystemHibernate) || (OldSystemPowerState == PowerSystemSleeping3) ) { BOOLEAN needsRescan;
PipReportStateChange(PiSWaitForKey); if ((fdoExtension->BusNumber == 0) && PipRDPNode && (PipRDPNode->Flags & (DF_ACTIVATED|DF_PROCESSING_RDP|DF_QUERY_STOPPED)) == DF_ACTIVATED) { needsRescan = PipMinimalCheckBus(fdoExtension); if (needsRescan) { PipRDPNode->Flags |= DF_NEEDS_RESCAN; IoInvalidateDeviceRelations( fdoExtension->PhysicalBusDevice, BusRelations); } } } #endif
}
IoSkipCurrentIrpStackLocation (irp); PoCallDriver (fdoExtension->AttachedDevice, irp);
} else {
PoStartNextPowerIrp (irp); IoCompleteRequest(irp, IO_NO_INCREMENT); }
return STATUS_SUCCESS; } // FdoContingentPowerCompletionRoutine
|