⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 power.c

📁 This is the library for all storage drivers. It simplifies writing a storage driver by implementing
💻 C
📖 第 1 页 / 共 4 页
字号:
        // 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 + -