📄 powerfdo.cpp
字号:
} // DestroyContext
///////////////////////////////////////////////////////////////////////
// SubPowerUpComplete is the action for a AsyncNotify event in the
// SubPowerUpPending state. This should be called from PoCompletionRoutine.
// We can also get here from SendDeviceIrp to avoid the Win98 no-D-IRP bug,
// in which case we don't want to alter "status" from its current value.
case SubPowerUpComplete:
{ // SubPowerUpComplete
if (status == -1)
status = STATUS_SUCCESS; // don't actually care, since called from PoCompletionRoutine
action = CompleteMainIrp;
continue;
} // SubPowerUpComplete
///////////////////////////////////////////////////////////////////////
// SubPowerDownComplete is the action for a AsyncNotify event in the
// SubPowerDownPending state. This should be called from PoCompletionRoutine.
// We can also get here from SendDeviceIrp to avoid the Win98 no-D-IRP bug,
// in which case we don't want to alter "status" from its current value.
case SubPowerDownComplete:
{ // SubPowerDownComplete
if (status == -1)
status = STATUS_SUCCESS; // don't actually care, since called from PoCompletionRoutine
if (NT_SUCCESS(ctx->status))
{
SETSTATE(SysPowerDownPending);
action = ForwardMainIrp;
}
else
action = CompleteMainIrp; // D-state IRP failed, so fail S-state IRP too
continue;
} // SubPowerDownComplete
///////////////////////////////////////////////////////////////////////
// DevPowerUpComplete is the action for a MainIrpComplete event in the
// DevPowerUpPending state. This should be called from MainCompletionRoutine
// when a device power-up IRP finishes in the lower layers.
case DevPowerUpComplete:
{ // DevPowerUpComplete
// If this IRP failed, or if we're just dealing with a query, we're done.
if (!NT_SUCCESS(ctx->status) || stack->MinorFunction != IRP_MN_SET_POWER)
{
action = CompleteMainIrp;
continue;
}
status = STATUS_MORE_PROCESSING_REQUIRED; // defer completion of the main IRP while we restore context
ctx->oldpower = pdx->devpower;
pdx->devpower = stack->Parameters.Power.State.DeviceState;
KdPrint((DRIVERNAME " - Now in %s\n", devstate[pdx->devpower]));
action = ContextRestoreComplete;
continue;
} // DevPowerUpComplete
///////////////////////////////////////////////////////////////////////
// ContextRestoreComplete is the last action for a device set power up
// operation. It's ordinarily reached when GenericSaveRestoreComplete
// signals a MainIrpComplete event from the ContextRestorePending state.
// It can also be reached directly from DevPowerUpComplete when there is
// no context restore function.
case ContextRestoreComplete:
{ // ContextRestoreComplete
if (event == AsyncNotify)
status = STATUS_SUCCESS; // doesn't actually matter
action = CompleteMainIrp;
// If the device IRP failed, just go ahead and let it complete. If we've
// successfully resumed to a sleeping state (> D0), skip restarting the
// substantive IRP queue and complete the IRP as well.
if (!NT_SUCCESS(ctx->status) || pdx->devpower != PowerDeviceD0)
continue;
ASSERT(stack->MinorFunction == IRP_MN_SET_POWER); // query should have gone directly to CompleteMainIrp from DevPowerUpComplete
continue;
} // ContextRestoreComplete
///////////////////////////////////////////////////////////////////////
// SaveContext initiates a context save operation if necessary. This will
// be the second action for a new device set-power IRP.
case SaveContext:
{ // SaveContext
ASSERT(stack->MinorFunction == IRP_MN_SET_POWER);
DEVICE_POWER_STATE devpower = stack->Parameters.Power.State.DeviceState;
action = ContextSaveComplete;
continue;
} // SaveContext
///////////////////////////////////////////////////////////////////////
// ContextSaveComplete is the action for an AsyncNotify event in the
// ContextSavePending state. It should be entered from GenericSaveRestoreComplete,
// which in turn should have been called by the client driver when its
// context save operation finished. It can also be entered directly from
// SaveContext when there is no context save routine.
case ContextSaveComplete:
{ // ContextSaveComplete
if (event == AsyncNotify)
status = STATUS_SUCCESS; // doesn't actually matter in this case
SETSTATE(DevPowerDownPending);
action = ForwardMainIrp;
ASSERT(stack);
DEVICE_POWER_STATE devpower = stack->Parameters.Power.State.DeviceState;
if (devpower <= pdx->devpower)
continue; // no actual change in device power
ASSERT(stack->MinorFunction == IRP_MN_SET_POWER);
pdx->devpower = devpower;
KdPrint((DRIVERNAME " - Now in %s\n", devstate[pdx->devpower]));
continue;
} // ContextSaveComplete
///////////////////////////////////////////////////////////////////////
// DevQueryUpComplete is the action for a MainIrpComplete event in the
// DevQueryUpPending state. This should be called by MainCompletionRoutine
// when a device query-power-up IRP completes. We don't expect to ever get this
// kind of a query, by the way, but we should handle it nontheless.
case DevQueryUpComplete:
{ // DevQueryUpComplete
if (NT_SUCCESS(ctx->status))
{ // ask client if change okay
// TODO replace the FALSE immediately below with some non-blocking test
// to see if it's okay to restore power. It would be very unusual to
// say "no". In making the test, pdx->devpower is the current power
// state and stack->Parameters.Power.State.DeviceState is the
// proposed new state.
if (FALSE)
ctx->status = STATUS_UNSUCCESSFUL; // fail the query
} // ask client if change okay
action = CompleteMainIrp;
continue;
} // DevQueryUpComplete
///////////////////////////////////////////////////////////////////////
// DevQueryDown is the second action (after TriageNewIrp) for a device
// query-power that specifies less than or equal to the current device
// power state.
case DevQueryDown:
{ // DevQueryDown
DEVICE_POWER_STATE devpower = stack->Parameters.Power.State.DeviceState;
// TODO replace the FALSE immediately below with some non-blocking test
// to see if it's okay to remove power. In making the test, pdx->devpower
// is the current power state and devpower is the proposed new state.
if (devpower > pdx->devpower && FALSE)
{ // fail the query
ctx->status = STATUS_UNSUCCESSFUL;
action = DevQueryDownComplete;
continue;
} // fail the query
SETSTATE(DevQueryDownPending);
action = ForwardMainIrp;
continue;
} // DevQueryDown
///////////////////////////////////////////////////////////////////////
// DevQueryDownComplete is the action for a MainIrpComplete event in the
// DevQueryDownPending state. It can be reached from MainCompletionRoutine
// or directly from DevQueryDown.
case DevQueryDownComplete:
{ // DevQueryDownComplete
action = CompleteMainIrp;
continue;
} // DevQueryDownComplete
///////////////////////////////////////////////////////////////////////
// InvalidAction is the action for any unexpected event. It should never occur.
case InvalidAction:
default:
ASSERT(FALSE);
status = STATUS_UNSUCCESSFUL;
break;
} // perform next action
break; // for cases that "break" from the switch
} // handle this event
// Check to make sure the state got changed before we exit
ASSERT(nextstate != originalstate);
// Check to make sure a valid status will be returned
ASSERT(status != -1);
return status;
} // HandlePowerEvent
///////////////////////////////////////////////////////////////////////////////
NTSTATUS MainCompletionRoutine(PDEVICE_OBJECT junk, PIRP Irp, PPOWCONTEXT ctx)
{ // MainCompletionRoutine
ctx->status = Irp->IoStatus.Status;
return HandlePowerEvent(ctx, MainIrpComplete);
} // MainCompletionRoutine
VOID PoCompletionRoutine(PDEVICE_OBJECT junk, UCHAR fcn, POWER_STATE state, PPOWCONTEXT ctx, PIO_STATUS_BLOCK pstatus)
{ // PoCompletionRoutine
ctx->status = pstatus->Status;
HandlePowerEvent(ctx, AsyncNotify);
} // PoCompletionRoutine
VOID PassivePowerCall(PIRP Irp)
{ // PassivePowerCall
PoCallDriver(IoGetNextIrpStackLocation(Irp)->DeviceObject, Irp);
} // PassivePowerCall
NTSTATUS SafePoCallDriver(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{ // SafePoCallDriver
// If running in Win2K, or if Win98 and already at PASSIVE_LEVEL, just call
// PoCallDriver.
if (!win98 || KeGetCurrentIrql() == PASSIVE_LEVEL)
return PoCallDriver(DeviceObject, Irp);
// Win98's PoCallDriver is the same as IoCallDriver, and it won't do anything to
// present the IRP at passive level if we're currently above. Build a work queue
// item in the DriverContext field of the IRP and queue the work item so we
// can present the IRP properly. Boy, is this something we shouldn't have to
// worry about!
IoMarkIrpPending(Irp); // be sure it's marked pending
IoGetNextIrpStackLocation(Irp)->DeviceObject = DeviceObject; // so PassivePowerCall can find it
// Note: The ExXxxWorkItem functions are deprecated for Win2K and WinXp but
// okay for win98. This code only executes in Win98, so these should be okay
#pragma warning(disable:4995)
#pragma warning(disable:4996)
PWORK_QUEUE_ITEM item = (PWORK_QUEUE_ITEM) Irp->Tail.Overlay.DriverContext;
ExInitializeWorkItem(item, (PWORKER_THREAD_ROUTINE) PassivePowerCall, (PVOID) Irp);
ExQueueWorkItem(item, DelayedWorkQueue);
return STATUS_PENDING;
} // SafePoCallDriver
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -