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 + -
显示快捷键?