|
|
/*++
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; }
|