windows-nt/Source/XPSP1/NT/base/busdrv/isapnp/power.c

735 lines
19 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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