mavpwr.c

来自「基于EP7312的MP3播放器源代码,包括MCU和PC端代码.」· C语言 代码 · 共 1,127 行 · 第 1/3 页

C
1,127
字号
//****************************************************************************
//
// Mavpwr.C - Routines to handle power management IRPs.
//
// Copyright (c) 2000 Cirrus Logic, Inc.
// Copyright (c) 1997-1998 Microsoft Corporation.  All Rights Reserved.
//   THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
//   KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//   IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
//   PURPOSE.
//
//****************************************************************************
#include "wdm.h"
#include "usbdi.h"
#include "usbdlib.h"
#include "mavusb.h"
#include "mavproto.h"

//****************************************************************************
//
// This is our FDO's dispatch table function for IRP_MJ_POWER.  It processes
// the Power IRPs sent to the PDO for this device.
//
// For every power IRP, drivers must call PoStartNextPowerIrp and use
// PoCallDriver to pass the IRP all the way down the driver stack to the
// underlying PDO.
//
// Arguments:
//
//     DeviceObject - pointer to our device object (FDO)
//
//     Irp - pointer to an I/O Request Packet
//
// Return Value:
//
//     NT status code
//
//****************************************************************************
NTSTATUS
MavUsb_ProcessPowerIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
    PIO_STACK_LOCATION irpStack;
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PDEVICE_EXTENSION deviceExtension;
    BOOLEAN fGoingToD0 = FALSE;
    POWER_STATE sysPowerState, desiredDevicePowerState;
    KEVENT event;

    //
    // Get a pointer to the device extension.
    //
    deviceExtension = DeviceObject->DeviceExtension;

    //
    // Get a pointer to the current location in the IRP stack.  This is where
    // the function codes and parameters are located.
    //
    irpStack = IoGetCurrentIrpStackLocation(Irp);

    //
    // Increment the count of pending IRPs.
    //
    MavUsb_IncrementIoCount(DeviceObject);

    //
    // Determine what to do based on the minor function in the IRP.
    //
    switch(irpStack->MinorFunction)
    {
        //
        // A driver sends IRP_MN_WAIT_WAKE to indicate that the system should
        // wait for its device to signal a wake event.  The exact nature of the
        // event is device-dependent.
        //
        // Drivers send this IRP for two reasons:
        //   1) To allow a device to wake the system
        //   2) To wake a device that has been put into a sleep state to save
        //      power but still must be able to communicate with its driver
        //      under certain circumstances.
        //
        // When a wake event occurs, the driver completes the IRP and returns
        // STATUS_SUCCESS.  If the device is sleeping when the event occurs,
        // the driver must first wake up the device before completing the IRP.
        // In a completion routine, the driver calls PoRequestPowerIrp to send
        // a PowerDeviceD0 request.  When the device has powered up, the driver
        // can handle the IRP_MN_WAIT_WAKE request.
        //
        case IRP_MN_WAIT_WAKE:
        {
            //
            // deviceExtension->DeviceCapabilities.DeviceWake specifies the
            // lowest device power state (least powered) from which the device
            // can signal a wake event.
            //
            deviceExtension->PowerDownLevel =
                deviceExtension->DeviceCapabilities.DeviceWake;

            //
            // See if the device is currently in a power state that can support
            // wakeup.
            //
            if((deviceExtension->CurrentDevicePowerState == PowerDeviceD0) ||
               (deviceExtension->DeviceCapabilities.DeviceWake >
                deviceExtension->CurrentDevicePowerState))
            {
                //
                // STATUS_INVALID_DEVICE_STATE is returned if the device in the
                // PowerD0 state or a state below which it can support waking,
                // or if the SystemWake state is below a state which can be
                // supported.  A pending IRP_MN_WAIT_WAKE will complete with
                // this error if the device's state is changed to be
                // incompatible with the wake request.
                //
                // If a driver fails this IRP, it should complete the IRP
                // immediately without passing the IRP to the next-lower
                // driver.
                //
                ntStatus = STATUS_INVALID_DEVICE_STATE;

                //
                // Set the status in the IRP.
                //
                Irp->IoStatus.Status = ntStatus;

                //
                // Complete the IRP.
                //
                IoCompleteRequest(Irp, IO_NO_INCREMENT);

                //
                // Decrement the pending IRP count.
                //
                MavUsb_DecrementIoCount(DeviceObject);

                //
                // Return the status.
                //
                return(ntStatus);
            }

            //
            // Flag we're enabled for wakeup.
            //
            deviceExtension->EnabledForWakeup = TRUE;

            //
            // Init an event for our completion routine to signal when PDO is
            // done with this IRP.
            //
            KeInitializeEvent(&event, NotificationEvent, FALSE);

            //
            // If not failing outright, pass this on to our PDO for further
            // handling.
            //
            IoCopyCurrentIrpStackLocationToNext(Irp);

            //
            // Set a completion routine so it can signal our event when the PDO
            // is done with the IRP.
            //
            IoSetCompletionRoutine(Irp, MavUsb_IrpCompletionRoutine, &event,
                                   TRUE, TRUE, TRUE);

            //
            // Prepare to send the IRP to the PDO.
            //
            PoStartNextPowerIrp(Irp);

            //
            // Send the IRP to the PDO.
            //
            ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject,
                                    Irp);

            //
            // If PDO is not done yet, wait for the event to be set in our
            // completion routine.
            //
            if(ntStatus == STATUS_PENDING)
            {
                //
                // Wait for the IRP to complete.
                //
                KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE,
                                      NULL);
            }

            //
            // Now tell the device to actually wake up.
            //
            MavUsb_SelfSuspendOrActivate(DeviceObject, FALSE);

            //
            // Flag we're done with the wakeup IRP.
            //
            deviceExtension->EnabledForWakeup = FALSE;

            //
            // Decrement the count of pending IRPs.
            //
            MavUsb_DecrementIoCount(DeviceObject);

            //
            // We're done with this IRP.
            //
            break;
        }

        //
        // The system power policy manager sends this IRP to set the system
        // power state.  A device power policy manager sends this IRP to set
        // the device power state for a device.
        //
        // Set Irp->IoStatus.Status to STATUS_SUCCESS to indicate that the
        // device has entered the requested state.  Drivers cannot fail this
        // IRP.
        //
        case IRP_MN_SET_POWER:
        {
            //
            // Is the system or device power state being set?
            //
            switch(irpStack->Parameters.Power.Type)
            {
                //
                // The system power state is being set.
                //
                case SystemPowerState:
                {
                    //
                    // Get input system power state.
                    //
                    sysPowerState.SystemState =
                        irpStack->Parameters.Power.State.SystemState;

                    //
                    // If system is in working state always set our device to
                    // D0 regardless of the wait state or system-to-device
                    // state power map.
                    //
                    if(sysPowerState.SystemState == PowerSystemWorking)
                    {
                        desiredDevicePowerState.DeviceState = PowerDeviceD0;
                    }
                    else
                    {
                        //
                        // Set to corresponding system state if a
                        // IRP_MN_WAIT_WAKE is pending.
                        //
                        if(deviceExtension->EnabledForWakeup)
                        {
                            //
                            // Find the device power state equivalent to the
                            // given system state.  We get this info from the
                            // DEVICE_CAPABILITIES struct in our device
                            // extension (initialized in
                            // MavUsb_PnPAddDevice()).
                            //
                            desiredDevicePowerState.DeviceState =
                                deviceExtension->DeviceCapabilities.
                                DeviceState[sysPowerState.SystemState];
                        }
                        else
                        {
                            //
                            // If no wait pending and the system's not in
                            // working state, just turn off.
                            //
                            desiredDevicePowerState.DeviceState =
                                PowerDeviceD3;
                        }
                    }

                    //
                    // We've determined the desired device state; are we
                    // already in this state?
                    //
                    if(desiredDevicePowerState.DeviceState !=
                       deviceExtension->CurrentDevicePowerState)
                    {
                        //
                        // No, request that we be put into this state by
                        // requesting a new Power IRP from the PnP manager.
                        //
                        deviceExtension->PowerIrp = Irp;
                        ntStatus =
                            PoRequestPowerIrp(deviceExtension->
                                              PhysicalDeviceObject,
                                              IRP_MN_SET_POWER,
                                              desiredDevicePowerState,
                                              MavUsb_PoRequestCompletion,
                                              DeviceObject, NULL);
                    }
                    else
                    {
                        //
                        // Yes, just pass it on to PDO (Physical Device
                        // Object).
                        //
                        IoCopyCurrentIrpStackLocationToNext(Irp);
                        PoStartNextPowerIrp(Irp);
                        ntStatus =
                            PoCallDriver(deviceExtension->
                                         TopOfStackDeviceObject, Irp);

                        //
                        // Decrement the count of pending IRPs.
                        //
                        MavUsb_DecrementIoCount(DeviceObject);
                    }

                    //
                    // We're done handling the system power state change.
                    //
                    break;
                }

                //
                // The device power state is being set.
                //
                case DevicePowerState:
                {
                    //
                    // For requests to D1, D2, or D3 (sleep or off states),
                    // sets deviceExtension->CurrentDevicePowerState to
                    // DeviceState immediately.  This enables any code checking
                    // state to consider us as sleeping or off already, as this
                    // will imminently become our state.
                    //
                    // For requests to DeviceState D0 (fully on), sets
                    // fGoingToD0 flag TRUE to flag that we must set a
                    // completion routine and update
                    // deviceExtension->CurrentDevicePowerState there.
                    //
                    // In the case of powering up to fully on, we really want
                    // to make sure the process is completed before updating
                    // our CurrentDevicePowerState, so no IO will be attempted
                    // or accepted before we're really ready.
                    //
                    fGoingToD0 =
                        MavUsb_SetDevicePowerState(DeviceObject,
                                                   irpStack->Parameters.Power.
                                                   State.DeviceState);

                    //
                    // Prepare to send the IRP to the PDO.
                    //
                    IoCopyCurrentIrpStackLocationToNext(Irp);

                    //
                    // If we are change to state D0, then set our completion
                    // routine.
                    //
                    if(fGoingToD0)
                    {
                        IoSetCompletionRoutine(Irp, MavUsb_PowerIrp_Complete,
                                               DeviceObject, TRUE, TRUE, TRUE);
                    }

                    //
                    // Send the IRP to the PDO.
                    //
                    PoStartNextPowerIrp(Irp);
                    ntStatus =
                        PoCallDriver(deviceExtension->TopOfStackDeviceObject,
                                     Irp);

                    //
                    // If we are not changing to state D0, then decrement the
                    // count of pending IRPs.
                    //
                    if(!fGoingToD0)
                    {
                        MavUsb_DecrementIoCount(DeviceObject);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?