Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

745 lines
19 KiB

/*++
Copyright (c) 2002 Microsoft Corporation
Module Name:
fdopower.c
Abstract:
This module contains code to handle
IRP_MJ_POWER dispatches for SD controllers
Authors:
Neil Sandlin (neilsa) Jan 1, 2002
Environment:
Kernel mode only
Notes:
Revision History:
--*/
#include "pch.h"
//
// Internal References
//
NTSTATUS
SdbusFdoSetSystemPowerState(
IN PDEVICE_OBJECT Fdo,
IN OUT PIRP Irp
);
VOID
SdbusFdoSetSystemPowerStateCompletion(
IN PDEVICE_OBJECT Fdo,
IN PVOID Context
);
NTSTATUS
SdbusFdoRequestDevicePowerState(
IN PDEVICE_OBJECT Fdo,
IN DEVICE_POWER_STATE DevicePowerState,
IN PSDBUS_COMPLETION_ROUTINE CompletionRoutine,
IN PVOID Context,
IN BOOLEAN WaitForRequestComplete
);
VOID
SdbusFdoSystemPowerDeviceIrpComplete(
IN PDEVICE_OBJECT Fdo,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
);
NTSTATUS
SdbusFdoSetDevicePowerState(
IN PDEVICE_OBJECT Fdo,
IN OUT PIRP Irp
);
NTSTATUS
SdbusFdoSetDevicePowerStateCompletion(
IN PDEVICE_OBJECT Fdo,
IN PIRP Irp,
IN PVOID Context
);
VOID
SdbusFdoSetDevicePowerStateActivateComplete(
IN PDEVICE_OBJECT Fdo,
IN PVOID Context,
IN NTSTATUS status
);
NTSTATUS
SdbusSetPdoDevicePowerState(
IN PDEVICE_OBJECT Pdo,
IN OUT PIRP Irp
);
VOID
SdbusPdoInitializeFunctionComplete(
IN PSD_WORK_PACKET WorkPacket,
IN NTSTATUS status
);
NTSTATUS
SdbusPdoCompletePowerIrp(
IN PPDO_EXTENSION pdoExtension,
IN PIRP Irp,
IN NTSTATUS status
);
//************************************************
//
// FDO Routines
//
//************************************************
NTSTATUS
SdbusSetFdoPowerState(
IN PDEVICE_OBJECT Fdo,
IN OUT PIRP Irp
)
/*++
Routine Description
Dispatches the IRP based on whether a system power state
or device power state transition is requested
Arguments
DeviceObject - Pointer to the functional device object for the sd controller
Irp - Pointer to the Irp for the power dispatch
Return value
status
--*/
{
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status;
if (irpStack->Parameters.Power.Type == DevicePowerState) {
status = SdbusFdoSetDevicePowerState(Fdo, Irp);
} else if (irpStack->Parameters.Power.Type == SystemPowerState) {
status = SdbusFdoSetSystemPowerState(Fdo, Irp);
} else {
status = Irp->IoStatus.Status;
PoStartNextPowerIrp (Irp);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return status;
}
NTSTATUS
SdbusFdoSetSystemPowerState(
IN PDEVICE_OBJECT Fdo,
IN OUT PIRP Irp
)
/*++
Routine Description
Handles system power state IRPs for the host controller.
Arguments
DeviceObject - Pointer to the functional device object for the sd controller
Irp - Pointer to the Irp for the power dispatch
Return value
status
--*/
{
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
SYSTEM_POWER_STATE newSystemState = irpStack->Parameters.Power.State.SystemState;
DEVICE_POWER_STATE devicePowerState;
NTSTATUS status = STATUS_SUCCESS;
BOOLEAN waitForCompletion = TRUE;
try{
//
// Validate new system state
//
if (newSystemState >= POWER_SYSTEM_MAXIMUM) {
status = STATUS_UNSUCCESSFUL;
leave;
}
//
// Switch to the appropriate device power state
//
devicePowerState = fdoExtension->DeviceCapabilities.DeviceState[newSystemState];
if (devicePowerState == PowerDeviceUnspecified) {
status = STATUS_UNSUCCESSFUL;
leave;
}
//
// Transitioned to system state
//
DebugPrint((SDBUS_DEBUG_POWER, "fdo %08x irp %08x transition S state %d => %d, sending D%d\n",
Fdo, Irp, fdoExtension->SystemPowerState-1, newSystemState-1, devicePowerState-1));
fdoExtension->SystemPowerState = newSystemState;
//
// Don't wait for completion if we are coming out of standby/hibernate
//
waitForCompletion = (newSystemState != PowerSystemWorking);
if (!waitForCompletion) {
IoMarkIrpPending(Irp);
}
status = SdbusFdoRequestDevicePowerState(fdoExtension->DeviceObject,
devicePowerState,
SdbusFdoSetSystemPowerStateCompletion,
Irp,
waitForCompletion);
} finally {
if (!NT_SUCCESS(status)) {
PoStartNextPowerIrp (Irp);
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
if (!waitForCompletion && (status != STATUS_PENDING)) {
//
// We've already marked the IRP pending, so we must return STATUS_PENDING
// (ie fail it asynchronously)
//
status = STATUS_PENDING;
}
}
DebugPrint((SDBUS_DEBUG_POWER, "fdo %08x irp %08x <-- %08x\n", Fdo, Irp, status));
return status;
}
VOID
SdbusFdoSetSystemPowerStateCompletion(
IN PDEVICE_OBJECT Fdo,
IN PVOID Context
)
/*++
Routine Description
Handles system power state IRPs for the host controller.
Arguments
DeviceObject - Pointer to the functional device object for the sd controller
Irp - Pointer to the Irp for the power dispatch
Return value
status
--*/
{
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
PIRP Irp = Context;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PoSetPowerState (Fdo, SystemPowerState, irpStack->Parameters.Power.State);
PoStartNextPowerIrp (Irp);
IoSkipCurrentIrpStackLocation(Irp);
PoCallDriver(fdoExtension->LowerDevice, Irp);
}
NTSTATUS
SdbusFdoRequestDevicePowerState(
IN PDEVICE_OBJECT Fdo,
IN DEVICE_POWER_STATE DevicePowerState,
IN PSDBUS_COMPLETION_ROUTINE CompletionRoutine,
IN PVOID Context,
IN BOOLEAN WaitForRequestComplete
)
/*++
Routine Description
This routine is called to request a new device power state for the FDO
Parameters
DeviceObject - Pointer to the Fdo for the SDBUS controller
PowerState - Power state requested
CompletionRoutine - Routine to be called when finished
Context - Context passed in to the completion routine
Return Value
Status
--*/
{
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
POWER_STATE powerState;
NTSTATUS status;
powerState.DeviceState = DevicePowerState;
if (!WaitForRequestComplete) {
//
// Call the completion routine immediately
//
(*CompletionRoutine)(Fdo, Context);
//
// Request the device power irp to be completed later
//
PoRequestPowerIrp(fdoExtension->DeviceObject, IRP_MN_SET_POWER, powerState, NULL, NULL, NULL);
status = STATUS_SUCCESS;
} else {
PSD_POWER_CONTEXT powerContext;
powerContext = ExAllocatePool(NonPagedPool, sizeof(SD_POWER_CONTEXT));
if (!powerContext) {
return STATUS_INSUFFICIENT_RESOURCES;
}
powerContext->CompletionRoutine = CompletionRoutine;
powerContext->Context = Context;
status = PoRequestPowerIrp(fdoExtension->DeviceObject,
IRP_MN_SET_POWER,
powerState,
SdbusFdoSystemPowerDeviceIrpComplete,
powerContext,
NULL
);
}
return status;
}
VOID
SdbusFdoSystemPowerDeviceIrpComplete(
IN PDEVICE_OBJECT Fdo,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
/*++
Routine Description
This routine is called on completion of a D irp generated by an S irp.
Parameters
DeviceObject - Pointer to the Fdo for the SDBUS controller
MinorFunction - Minor function of the IRP_MJ_POWER request
PowerState - Power state requested
Context - Context passed in to the completion routine
IoStatus - Pointer to the status block which will contain
the returned status
Return Value
Status
--*/
{
PSD_POWER_CONTEXT powerContext = Context;
// DebugPrint((SDBUS_DEBUG_POWER, "fdo %08x irp %08x request for D%d complete, passing S irp down\n",
// Fdo, Irp, PowerState.DeviceState-1));
(*powerContext->CompletionRoutine)(Fdo, powerContext->Context);
ExFreePool(powerContext);
}
NTSTATUS
SdbusFdoSetDevicePowerState(
IN PDEVICE_OBJECT Fdo,
IN OUT PIRP Irp
)
/*++
Routine Description
Handles device power state IRPs for the pccard controller.
Arguments
DeviceObject - Pointer to the functional device object for the sd controller
Irp - Pointer to the Irp for the power dispatch
Return value
status
--*/
{
NTSTATUS status;
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
DEVICE_POWER_STATE devicePowerState = irpStack->Parameters.Power.State.DeviceState;
status = IoAcquireRemoveLock(&fdoExtension->RemoveLock, "Sdbu");
if (!NT_SUCCESS(status)) {
PoStartNextPowerIrp (Irp);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
if (devicePowerState != PowerDeviceD0) {
(*(fdoExtension->FunctionBlock->DisableEvent))(fdoExtension, SDBUS_EVENT_ALL);
//
// Turn card off
//
(*(fdoExtension->FunctionBlock->SetPower))(fdoExtension, FALSE, NULL);
}
// anything to do here?
// Perform any device-specific tasks that must be done before device power is removed,
// such as closing the device, completing or flushing any pending I/O, disabling interrupts,
// queuing subsequent incoming IRPs, and saving device context from which to restore or
// reinitialize the device.
// The driver should not cause a long delay (for example, a delay that a user might find
// unreasonable for this type of device) while handling the IRP.
// The driver should queue any incoming I/O requests until the device has returned to the working state.
IoMarkIrpPending(Irp);
IoCopyCurrentIrpStackLocationToNext (Irp);
//
// Set our completion routine in the Irp..
//
IoSetCompletionRoutine(Irp,
SdbusFdoSetDevicePowerStateCompletion,
Fdo,
TRUE,
TRUE,
TRUE);
PoCallDriver(fdoExtension->LowerDevice, Irp);
return STATUS_PENDING;
}
NTSTATUS
SdbusFdoSetDevicePowerStateCompletion(
IN PDEVICE_OBJECT Fdo,
IN PIRP Irp,
IN PVOID Context
)
{
NTSTATUS status;
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
DEVICE_POWER_STATE devicePowerState = irpStack->Parameters.Power.State.DeviceState;
PSD_WORK_PACKET workPacket;
BOOLEAN cardInSlot;
BOOLEAN completeDeviceIrp;
try{
if (devicePowerState != PowerDeviceD0) {
completeDeviceIrp = TRUE;
status = Irp->IoStatus.Status;
leave;
}
//
// powering up
//
(*(fdoExtension->FunctionBlock->InitController))(fdoExtension);
(*(fdoExtension->FunctionBlock->EnableEvent))(fdoExtension, (SDBUS_EVENT_INSERTION | SDBUS_EVENT_REMOVAL));
SdbusActivateSocket(Fdo, SdbusFdoSetDevicePowerStateActivateComplete, Irp);
completeDeviceIrp = FALSE;
status = STATUS_MORE_PROCESSING_REQUIRED;
} finally {
if (completeDeviceIrp) {
PoSetPowerState(Fdo, DevicePowerState, irpStack->Parameters.Power.State);
PoStartNextPowerIrp (Irp);
IoReleaseRemoveLock(&fdoExtension->RemoveLock, "Sdbu");
}
}
return status;
}
VOID
SdbusFdoSetDevicePowerStateActivateComplete(
IN PDEVICE_OBJECT Fdo,
IN PVOID Context,
IN NTSTATUS status
)
{
PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
PIRP Irp = Context;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PoSetPowerState(Fdo, DevicePowerState, irpStack->Parameters.Power.State);
PoStartNextPowerIrp(Irp);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
//************************************************
//
// PDO Routines
//
//************************************************
NTSTATUS
SdbusSetPdoPowerState(
IN PDEVICE_OBJECT Pdo,
IN OUT PIRP Irp
)
/*++
Routine Description
Dispatches the IRP based on whether a system power state
or device power state transition is requested
Arguments
Pdo - Pointer to the physical device object for the pc-card
Irp - Pointer to the Irp for the power dispatch
Return value
status
--*/
{
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
PFDO_EXTENSION fdoExtension = pdoExtension->FdoExtension;
NTSTATUS status;
switch (irpStack->Parameters.Power.Type) {
case DevicePowerState:
status = SdbusSetPdoDevicePowerState(Pdo, Irp);
break;
case SystemPowerState:
pdoExtension->SystemPowerState = irpStack->Parameters.Power.State.SystemState;
status = SdbusPdoCompletePowerIrp(pdoExtension, Irp, STATUS_SUCCESS);
break;
default:
status = SdbusPdoCompletePowerIrp(pdoExtension, Irp, Irp->IoStatus.Status);
}
return status;
}
NTSTATUS
SdbusSetPdoDevicePowerState(
IN PDEVICE_OBJECT Pdo,
IN OUT PIRP Irp
)
/*++
Routine Description
Handles the device power state transition for the given SD function.
Arguments
Pdo - Pointer to the physical device object for the SD function
Irp - Irp for the system state transition
Return value
status
--*/
{
PPDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
PFDO_EXTENSION fdoExtension = pdoExtension->FdoExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
DEVICE_POWER_STATE newDevicePowerState;
POWER_STATE newPowerState;
NTSTATUS status;
newDevicePowerState = irpStack->Parameters.Power.State.DeviceState;
DebugPrint((SDBUS_DEBUG_POWER, "pdo %08x transitioning D state %d => %d\n",
Pdo, pdoExtension->DevicePowerState, newDevicePowerState));
if (newDevicePowerState == pdoExtension->DevicePowerState) {
status = SdbusPdoCompletePowerIrp(pdoExtension, Irp, STATUS_SUCCESS);
return status;
}
if (newDevicePowerState == PowerDeviceD0) {
PSD_WORK_PACKET workPacket;
//
// Power up, initialize function
//
status = SdbusBuildWorkPacket(fdoExtension,
SDWP_INITIALIZE_FUNCTION,
SdbusPdoInitializeFunctionComplete,
Irp,
&workPacket);
if (!NT_SUCCESS(status)) {
status = SdbusPdoCompletePowerIrp(pdoExtension, Irp, status);
} else {
IoMarkIrpPending(Irp);
workPacket->PdoExtension = pdoExtension;
SdbusQueueWorkPacket(fdoExtension, workPacket, WP_TYPE_SYSTEM);
status = STATUS_PENDING;
}
} else {
//
// moving to a low power state
//
newPowerState.DeviceState = newDevicePowerState;
PoSetPowerState(Pdo, DevicePowerState, newPowerState);
pdoExtension->DevicePowerState = newDevicePowerState;
status = SdbusPdoCompletePowerIrp(pdoExtension, Irp, STATUS_SUCCESS);
}
return status;
}
VOID
SdbusPdoInitializeFunctionComplete(
IN PSD_WORK_PACKET WorkPacket,
IN NTSTATUS status
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PPDO_EXTENSION pdoExtension = WorkPacket->PdoExtension;
PIRP Irp = WorkPacket->CompletionContext;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
DEVICE_POWER_STATE newDevicePowerState;
POWER_STATE newPowerState;
newDevicePowerState = irpStack->Parameters.Power.State.DeviceState;
newPowerState.DeviceState = newDevicePowerState;
PoSetPowerState(pdoExtension->DeviceObject, DevicePowerState, newPowerState);
pdoExtension->DevicePowerState = newDevicePowerState;
SdbusPdoCompletePowerIrp(pdoExtension, Irp, status);
}
NTSTATUS
SdbusPdoCompletePowerIrp(
IN PPDO_EXTENSION pdoExtension,
IN PIRP Irp,
IN NTSTATUS status
)
/*++
Routine Description
Completion routine for the Power Irp directed to the PDO of the
SD function.
Arguments
DeviceObject - Pointer to the PDO for the SD function
Irp - Irp that needs to be completed
Return Value
status
--*/
{
InterlockedDecrement(&pdoExtension->DeletionLock);
Irp->IoStatus.Status = status;
PoStartNextPowerIrp(Irp);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}