📄 power.c
字号:
// We need to issue a queue lock request so that we
// can spin the drive back up after the power is restored
// but before any requests are processed.
//
context->Options.PowerDown = FALSE;
context->PowerChangeState.PowerUp = PowerUpDeviceInitial;
context->CompletionRoutine = ClasspPowerUpCompletion;
} else {
ASSERT(Options.HandleSpinDown);
fdoExtension->PowerDownInProgress = TRUE;
DebugPrint((2, "(%p)\tPowering down - locking queue\n", Irp));
PoSetPowerState(DeviceObject,
irpStack->Parameters.Power.Type,
irpStack->Parameters.Power.State);
context->Options.PowerDown = TRUE;
context->PowerChangeState.PowerDown2 = PowerDownDeviceInitial2;
context->CompletionRoutine = ClasspPowerDownCompletion;
}
//
// we are not dealing with port-allocated sense in these routines.
//
ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
ASSERT(!TEST_FLAG(context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
//
// we are always returning STATUS_PENDING, so we need to always
// set the irp as pending.
//
IoMarkIrpPending(Irp);
if(Options.LockQueue) {
//
// Send the lock irp down.
//
IoSetCompletionRoutine(Irp,
context->CompletionRoutine,
context,
TRUE,
TRUE,
TRUE);
IoCallDriver(lowerDevice, Irp);
} else {
//
// Call the completion routine directly. It won't care what the
// status of the "lock" was - it will just go and do the next
// step of the operation.
//
context->CompletionRoutine(DeviceObject, Irp, context);
}
return STATUS_PENDING;
ClasspPowerHandlerCleanup:
ClassReleaseRemoveLock(DeviceObject, Irp);
DebugPrint((1, "(%p)\tStarting next power irp\n", Irp));
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
ClasspStartNextPowerIrpCompletion,
NULL,
TRUE,
TRUE,
TRUE);
return PoCallDriver(lowerDevice, Irp);
} // end ClasspPowerHandler()
/*++////////////////////////////////////////////////////////////////////////////
ClassMinimalPowerHandler()
Routine Description:
This routine is the minimum power handler for a storage driver. It does
the least amount of work possible.
--*/
NTSTATUS
ClassMinimalPowerHandler(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status;
ClassReleaseRemoveLock(DeviceObject, Irp);
PoStartNextPowerIrp(Irp);
switch (irpStack->MinorFunction)
{
case IRP_MN_SET_POWER:
{
switch (irpStack->Parameters.Power.ShutdownType)
{
case PowerActionSleep:
case PowerActionHibernate:
{
if (TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA))
{
if ((ClassGetVpb(DeviceObject) != NULL) && (ClassGetVpb(DeviceObject)->Flags & VPB_MOUNTED))
{
//
// This flag will cause the filesystem to verify the
// volume when coming out of hibernation or standby
//
SET_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME);
}
}
}
break;
}
}
//
// Fall through
//
case IRP_MN_QUERY_POWER:
{
if (!commonExtension->IsFdo)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
}
}
break;
}
if (commonExtension->IsFdo)
{
IoCopyCurrentIrpStackLocationToNext(Irp);
status = PoCallDriver(commonExtension->LowerDeviceObject, Irp);
}
else
{
status = Irp->IoStatus.Status;
ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
}
return status;
} // end ClassMinimalPowerHandler()
/*++////////////////////////////////////////////////////////////////////////////
ClassSpinDownPowerHandler()
Routine Description:
This routine is a callback for disks and other things which require both
a start and a stop to be sent to the device. (actually the starts are
almost always optional, since most device power themselves on to process
commands, but i digress).
Determines proper use of spinup, spindown, and queue locking based upon
ScanForSpecialFlags in the FdoExtension. This is the most common power
handler passed into classpnp.sys
Arguments:
DeviceObject - Supplies the functional device object
Irp - Supplies the request to be retried.
Return Value:
None
--*/
NTSTATUS
ClassSpinDownPowerHandler(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
CLASS_POWER_OPTIONS options = {0};
fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// check the flags to see what options we need to worry about
//
if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
CLASS_SPECIAL_DISABLE_SPIN_DOWN)) {
options.HandleSpinDown = TRUE;
}
if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
CLASS_SPECIAL_DISABLE_SPIN_UP)) {
options.HandleSpinUp = TRUE;
}
if (!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
CLASS_SPECIAL_NO_QUEUE_LOCK)) {
options.LockQueue = TRUE;
}
DebugPrint((3, "ClasspPowerHandler: Devobj %p\n"
"\t%shandling spin down\n"
"\t%shandling spin up\n"
"\t%slocking queue\n",
DeviceObject,
(options.HandleSpinDown ? "" : "not "),
(options.HandleSpinUp ? "" : "not "),
(options.LockQueue ? "" : "not ")
));
//
// do all the dirty work
//
return ClasspPowerHandler(DeviceObject, Irp, options);
} // end ClassSpinDownPowerHandler()
/*++////////////////////////////////////////////////////////////////////////////
ClassStopUnitPowerHandler()
Routine Description:
This routine is an outdated call. To achieve equivalent functionality,
the driver should set the following flags in ScanForSpecialFlags in the
FdoExtension:
CLASS_SPECIAL_DISABLE_SPIN_UP
CLASS_SPECIAL_NO_QUEUE_LOCK
--*/
NTSTATUS
ClassStopUnitPowerHandler(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
DebugPrint((0, "ClassStopUnitPowerHandler - Devobj %p using outdated call\n"
"Drivers should set the following flags in ScanForSpecialFlags "
" in the FDO extension:\n"
"\tCLASS_SPECIAL_DISABLE_SPIN_UP\n"
"\tCLASS_SPECIAL_NO_QUEUE_LOCK\n"
"This will provide equivalent functionality if the power "
"routine is then set to ClassSpinDownPowerHandler\n\n",
DeviceObject));
fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
SET_FLAG(fdoExtension->ScanForSpecialFlags,
CLASS_SPECIAL_DISABLE_SPIN_UP);
SET_FLAG(fdoExtension->ScanForSpecialFlags,
CLASS_SPECIAL_NO_QUEUE_LOCK);
return ClassSpinDownPowerHandler(DeviceObject, Irp);
} // end ClassStopUnitPowerHandler()
/*++////////////////////////////////////////////////////////////////////////////
RetryPowerRequest()
Routine Description:
This routine reinitalizes the necessary fields, and sends the request
to the lower driver.
Arguments:
DeviceObject - Supplies the device object associated with this request.
Irp - Supplies the request to be retried.
Context - Supplies a pointer to the power up context for this request.
Return Value:
None
--*/
VOID
RetryPowerRequest(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PCLASS_POWER_CONTEXT Context
)
{
PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
PSCSI_REQUEST_BLOCK srb = &(Context->Srb);
LARGE_INTEGER dueTime;
DebugPrint((1, "(%p)\tDelaying retry by queueing DPC\n", Irp));
ASSERT(Context->Irp == Irp);
ASSERT(Context->DeviceObject == DeviceObject);
ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
ASSERT(!TEST_FLAG(Context->Srb.SrbFlags, SRB_FLAGS_PORT_DRIVER_ALLOCSENSE));
//
// reset the retry interval
//
Context->RetryInterval = 0;
//
// Reset byte count of transfer in SRB Extension.
//
srb->DataTransferLength = 0;
//
// Zero SRB statuses.
//
srb->SrbStatus = srb->ScsiStatus = 0;
//
// Set up major SCSI function.
//
nextIrpStack->MajorFunction = IRP_MJ_SCSI;
//
// Save SRB address in next stack for port driver.
//
nextIrpStack->Parameters.Scsi.Srb = srb;
//
// Set the completion routine up again.
//
IoSetCompletionRoutine(Irp, Context->CompletionRoutine, Context,
TRUE, TRUE, TRUE);
if (Context->RetryInterval == 0) {
DebugPrint((2, "(%p)\tDelaying minimum time (.2 sec)\n", Irp));
dueTime.QuadPart = (LONGLONG)1000000 * 2;
} else {
DebugPrint((2, "(%p)\tDelaying %x seconds\n",
Irp, Context->RetryInterval));
dueTime.QuadPart = (LONGLONG)1000000 * 10 * Context->RetryInterval;
}
ClassRetryRequest(DeviceObject, Irp, dueTime);
return;
} // end RetryRequest()
/*++////////////////////////////////////////////////////////////////////////////
ClasspStartNextPowerIrpCompletion()
Routine Description:
This routine guarantees that the next power irp (power up or down) is not
sent until the previous one has fully completed.
--*/
NTSTATUS
ClasspStartNextPowerIrpCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
if(Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
PoStartNextPowerIrp(Irp);
return STATUS_SUCCESS;
} // end ClasspStartNextPowerIrpCompletion()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -