📄 usbfx2lk_selsusp.cpp
字号:
//
// Setup the power up state to be D0
//
devicePowerState.DeviceState = PowerDeviceD0;
//
// Initialize the power up event that our power completion
// routine will signal when the power up is complete
//
KeInitializeEvent(&powerUpCompleteEvent, NotificationEvent, FALSE);
//
// And ask the power manager to create and send a power up D-IRP
// to our PDO. Specify the synchronous power completion routine,
// which will simply set the event that we pass to it when it
// runs
//
status = PoRequestPowerIrp(DevExt->PhysicalDeviceObject,
IRP_MN_SET_POWER,
devicePowerState,
SSSynchronousPowerIrpCompletionFunc,
&powerUpCompleteEvent,
NULL);
//
// We want to do this operation synchronously, so just wait
// for the operation to complete
//
if (status == STATUS_PENDING) {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_SELECTIVE_SUSPEND,
("SSPowerUpDevice: Waiting for the power irp to complete\n"));
OsrWaitForSingleObject(&powerUpCompleteEvent);
}
//
// The I/O is finished.
//
OsrDecrementOutstandingIoCount(DevExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_SELECTIVE_SUSPEND,
("SSPowerUpDevice: PoRequestPowerIrp returned 0x%x (%s).\n",
status,OsrNtStatusToString(status)));
//
// A power up is complete, get the Selective Suspend
// state properly updated
//
SSPowerUpCompleteUpdateSSState(DevExt);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_SELECTIVE_SUSPEND,
("SSPowerUpDevice: Exited\n"));
}
///////////////////////////////////////////////////////////////////////////////
//
// SSPowerUpCompleteUpdateSSState
//
// This routine updates the Selective Suspend state of the device
// after a power up operation is complete
//
// INPUTS:
//
// DevExt - One of our device extensions
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// Arbitrary
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
VOID SSPowerUpCompleteUpdateSSState(PUSBFX2LK_EXT DevExt)
{
KIRQL oldIrql;
//
// If someone has called here then we've just finished
// a power up so we need to update the SS state
// based on whether or not the power up actually
// happened
//
KeAcquireSpinLock(&DevExt->SSLock,&oldIrql);
if (DevExt->DevicePowerState != PowerDeviceD0) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_SELECTIVE_SUSPEND,
("SSPowerUpDevice: Power up of device did not succeed. Device "\
"power state is 0x%x\n",
DevExt->DevicePowerState));
//
// Indicate that we're suspended.
//
DevExt->SSState = SS_SUSPENDED;
} else {
//
// Device is now powered up!
//
DevExt->SSState = SS_NOT_STARTED;
}
//
// Set the "device is now out of selective suspend" event
//
KeSetEvent(&DevExt->SSDeviceNotSuspendedEvent,
EVENT_INCREMENT,
FALSE);
KeReleaseSpinLock(&DevExt->SSLock,oldIrql);
//
// Restart any requests that may have been queued
// while the device was powering down.
//
OsrProcessQueuedRequests(DevExt);
}
///////////////////////////////////////////////////////////////////////////////
//
// SSPowerUpDeviceAsync
//
// This routine asynchronously powers up the device
//
// INPUTS:
//
// DevExt - One of our device extensions
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// Arbitrary
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
VOID SSPowerUpDeviceAsync(PUSBFX2LK_EXT DevExt)
{
POWER_STATE devicePowerState;
NTSTATUS status;
KIRQL oldIrql;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_SELECTIVE_SUSPEND,
("SSPowerUpDeviceAsync: Entered\n"));
//
// We should not already be in D0 at this point
//
ASSERT(DevExt->DevicePowerState != PowerDeviceD0);
//
// Submit a device power IRP to our device
//
//
// This constitutes a new I/O on the device,
// so bump the oustanding I/O count
//
OsrIncrementOutstandingIoCount(DevExt,__FILE__,__LINE__);
//
// Setup the power up state to be D0
//
devicePowerState.DeviceState = PowerDeviceD0;
//
// And ask the power manager to create and send a power up D-IRP
// to our PDO. Specify the asynchronous power completion routine
// which will deal with getting the SS state updated when the
// IRP is completed.
//
status = PoRequestPowerIrp(DevExt->PhysicalDeviceObject,
IRP_MN_SET_POWER,
devicePowerState,
SSAsynchronousPowerUpIrpCompletionFunc,
DevExt,
NULL);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_SELECTIVE_SUSPEND,
("SSPowerUpDeviceAsync: PoRequestPowerIrp returned 0x%x (%s).\n",
status,OsrNtStatusToString(status)));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_SELECTIVE_SUSPEND,
("SSPowerUpDeviceAsync: Exited\n"));
}
///////////////////////////////////////////////////////////////////////////////
//
// SSSuspendDevice
//
// This routine synchronously suspends the device
//
// INPUTS:
//
// DevExt - One of our device extensions
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// Arbitrary
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
VOID SSSuspendDevice(PUSBFX2LK_EXT DevExt)
{
POWER_STATE devicePowerState;
KEVENT powerDownCompleteEvent;
NTSTATUS status;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_SELECTIVE_SUSPEND,
("SSSuspendDevice: Entered\n"));
//
// If we haven't figured out the power state
// that we're going to suspend to then we can't
// suspend. This may happen while the device is first starting
// up.
//
// Also, if we're already powered down there's no point in
// trying to power down again.
//
if (DevExt->PowerDownLevel == PowerDeviceUnspecified ||
DevExt->DevicePowerState != PowerDeviceD0) {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_SELECTIVE_SUSPEND,
("SSSuspendDevice: PowerDownLevel not set or already "\
"suspended, not suspending\n"));
return;
}
//
// Submit a device power IRP to our device
//
//
// This constitutes a new I/O on the device,
// so bump the oustanding I/O count
//
OsrIncrementOutstandingIoCount(DevExt,__FILE__,__LINE__);
//
// Setup the power down state to be the state
// that we determined during the QUERY_CAPABILITIES
// processing
//
devicePowerState.DeviceState = (DEVICE_POWER_STATE)DevExt->PowerDownLevel;
//
// Initialize the power down event that our power completion
// routine will signal when the power down is complete
//
KeInitializeEvent(&powerDownCompleteEvent, NotificationEvent, FALSE);
//
// And ask the power manager to create and send a power down D-IRP
// to our PDO. We always power the device down synchronously, so
// specify the synchronous power completion routine and pass
// an event to be set.
//
status = PoRequestPowerIrp(DevExt->PhysicalDeviceObject,
IRP_MN_SET_POWER,
devicePowerState,
SSSynchronousPowerIrpCompletionFunc,
&powerDownCompleteEvent,
NULL);
//
// We want to do this operation synchronously, so just wait
// for the operation to complete
//
if (status == STATUS_PENDING) {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_SELECTIVE_SUSPEND,
("SSSuspendDevice: Waiting for the power irp to complete\n"));
OsrWaitForSingleObject(&powerDownCompleteEvent);
}
//
// The I/O is finished.
//
OsrDecrementOutstandingIoCount(DevExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_SELECTIVE_SUSPEND,
("SSSuspendDevice: PoRequestPowerIrp returned 0x%x (%s). Exiting...\n",
status,OsrNtStatusToString(status)));
//
// Unlike the power UP case, we don't try to determine if the power
// down actually happened and update the SS state. This is because
// in the power up case there's no concept of, "hey, I didn't want that
// power up!" as there is in the power down case. So, it is the caller's
// responsiblity to determine that if at any point during the power down
// the power down request was cancelled and that the device actually
// needs to be powered up again. Basically, more decisions need to be
// made before we can get out of the SS_PROCESSING state so we just
// return to the caller and let him deal with it.
//
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_SELECTIVE_SUSPEND,
("SSSuspendDevice: Exited\n"));
}
#ifndef W2K
///////////////////////////////////////////////////////////////////////////////
//
// SSSuspendDeviceWithCallback
//
// This routine requests an idle notification callback from the bus driver
// and uses it to synchronously power down the device
//
// INPUTS:
//
// DevExt - One of our device extensions
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// Arbitrary
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
VOID SSSuspendDeviceWithCallback(PUSBFX2LK_EXT DevExt)
{
PIRP idleCallbackIrp;
PIO_STACK_LOCATION nextStack;
NTSTATUS status;
KIRQL oldIrql;
PVOID waitObjects[2];
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_SELECTIVE_SUSPEND,
("SSSuspendDeviceWithCallback: Entered\n"));
//
// We're built for XP and later, so we need to
// submit an idle callback request and wait
// for the callback to be called by the bus
// driver before powering down the device
//
//
// There's one REALLY annoying side effect of us
// having to go through this path:
//
// ** There's no guarantee that the IRP won't complete
// ** in error before, DURING, or after the idle
// ** callback running. Also, in the successful
// ** case, the IRP's completion routine doesn't
// ** run until the device is powered back up again
//
// So, the idle callback may or may not ever run and
// the IRP's completion routine may run now or
// 48 hours in the future. However, we still want
// to supply seemingly synchronous power down behaviour
// even when we require the use of the idle callback
// (again, SS is hard enough so we're not going to
// optimize).
//
// We'll use 2 events to do this. One that will be fired
// within the callback (which, in the normal case, will
// run within a relatively short time) and one event for
// the running of the IRP's completion routine.
//
// If the event from the callback routine gets fired,
// then the device is powered down and we're set. If the
// event from the completion routine gets fired, then the
// idle IRP was aborted by the bus driver for some reason.
//
//
// Set the events to a known state
//
KeClearEvent(&DevExt->SSIdleCallbackCalled);
KeClearEvent(&DevExt->SSIdleCompletionRoutineCalled);
//
// Fill in the idle callback structure that we need
// to pass along with the IRP
//
DevExt->SSIdleCallbackInfo.IdleCallback = SSUsbIdleCallback;
DevExt->SSIdleCallbackInfo.IdleContext = DevExt;
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -