📄 pwr.c
字号:
/*
**********************************************************************
* Micrium, Inc.
* 949 Crestview Circle
* Weston, FL 33327-1848
*
* uC/USB-Bulk
*
* (c) Copyright 2003 - 2004, Micrium, Inc.
* All rights reserved.
*
***********************************************************************
----------------------------------------------------------------------
File : pwr.c
Purpose : Part of the USB bulk driver
---------------------------END-OF-HEADER------------------------------
*/
#include "Main.h"
typedef struct _WORKER_THREAD_CONTEXT {
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
PIO_WORKITEM WorkItem;
} WORKER_THREAD_CONTEXT, *PWORKER_THREAD_CONTEXT;
typedef struct _POWER_COMPLETION_CONTEXT {
PDEVICE_OBJECT DeviceObject;
PIRP SIrp;
} POWER_COMPLETION_CONTEXT, *PPOWER_COMPLETION_CONTEXT;
/*++
Routine Description:
This routine is the completion routine for device power DOWN irp.
Arguments:
DeviceObject - pointer to device object
Irp - I/O request packet
DeviceExtension - pointer to device extension
Return Value:
NT status value
--*/
NTSTATUS FinishDevPoDnIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp,IN DEVICE_EXTENSION * DeviceExtension) {
NTSTATUS ntS;
POWER_STATE newState;
PIO_STACK_LOCATION irpStack;
//
// initialize variables
//
ntS = Irp->IoStatus.Status;
irpStack = IoGetCurrentIrpStackLocation(Irp);
newState = irpStack->Parameters.Power.State;
DPRINT(("FinishDevPoDnIrp - begins\n"));
if(NT_SUCCESS(ntS) && irpStack->MinorFunction == IRP_MN_SET_POWER) {
//
// update the cache;
//
DPRINT(("updating cache..\n"));
DeviceExtension->DevPower = newState.DeviceState;
PoSetPowerState(DeviceObject, DevicePowerState, newState);
}
PoStartNextPowerIrp(Irp);
DPRINT(("FinishDevPoDnIrp::"));
DevIoDecrement(DeviceExtension);
DPRINT(("FinishDevPoDnIrp - ends\n"));
return STATUS_SUCCESS;
}
/*********************************************************************
*
* Routine Description:
*
* This routine waits for the I/O in progress to finish and then
* sends the device power irp (query/set) down the stack.
*
* Arguments:
*
* DeviceObject - pointer to device object
* Context - context passed to the work-item.
*
* Return Value:
*
* None
*/
VOID HoldIoRequestsWorkerRoutine(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context) {
PIRP irp;
NTSTATUS ntS;
DEVICE_EXTENSION * deviceExtension;
PWORKER_THREAD_CONTEXT context;
DPRINT(("HoldIoRequestsWorkerRoutine - begins\n"));
//
// initialize variables
//
deviceExtension = (DEVICE_EXTENSION *) DeviceObject->DeviceExtension;
context = (PWORKER_THREAD_CONTEXT) Context;
irp = (PIRP) context->Irp;
//
// wait for I/O in progress to finish.
// the stop event is signalled when the counter drops to 1.
// invoke DevIoDecrement twice: once each for the S-Irp and D-Irp.
//
DPRINT(("HoldIoRequestsWorkerRoutine::"));
DevIoDecrement(deviceExtension);
DPRINT(("HoldIoRequestsWorkerRoutine::"));
DevIoDecrement(deviceExtension);
KeWaitForSingleObject(&deviceExtension->StopEvent, Executive, KernelMode, FALSE, NULL);
//
// Increment twice to restore the count
//
DPRINT(("HoldIoRequestsWorkerRoutine::"));
DevIoIncrement(deviceExtension);
DPRINT(("HoldIoRequestsWorkerRoutine::"));
DevIoIncrement(deviceExtension);
//
// now send the Irp down
//
IoCopyCurrentIrpStackLocationToNext(irp);
IoSetCompletionRoutine(irp, (PIO_COMPLETION_ROUTINE) FinishDevPoDnIrp,
deviceExtension, TRUE, TRUE, TRUE);
ntS = PoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
if(!NT_SUCCESS(ntS)) {
DPRINT(("Lower driver fail a power Irp\n"));
}
IoFreeWorkItem(context->WorkItem);
ExFreePool((PVOID)context);
DPRINT(("HoldIoRequestsWorkerRoutine - ends\n"));
}
/*********************************************************************
* Routine Description:
*
* This routine is called on query or set power DOWN irp for the device.
* This routine queues a workitem.
* Arguments:
* DeviceObject - pointer to device object
* Irp - I/O request packet
*
* Return Value:
* NT status value
*/
NTSTATUS HoldIoRequests(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp) {
NTSTATUS ntS;
PIO_WORKITEM item;
DEVICE_EXTENSION * deviceExtension;
PWORKER_THREAD_CONTEXT context;
//
// initialize variables
//
deviceExtension = (DEVICE_EXTENSION *) DeviceObject->DeviceExtension;
DPRINT(("HoldIoRequests - begins\n"));
deviceExtension->QueueState = HoldRequests;
context = ExAllocatePool(NonPagedPool, sizeof(WORKER_THREAD_CONTEXT));
if(context) {
item = IoAllocateWorkItem(DeviceObject);
context->Irp = Irp;
context->DeviceObject = DeviceObject;
context->WorkItem = item;
if(item) {
IoMarkIrpPending(Irp);
IoQueueWorkItem(item, HoldIoRequestsWorkerRoutine,
DelayedWorkQueue, context);
ntS = STATUS_PENDING;
} else {
DPRINT(("Failed to allocate memory for workitem\n"));
ExFreePool(context);
ntS = STATUS_INSUFFICIENT_RESOURCES;
}
} else {
DPRINT(("Failed to alloc memory for worker thread context\n"));
ntS = STATUS_INSUFFICIENT_RESOURCES;
}
DPRINT(("HoldIoRequests - ends\n"));
return ntS;
}
/*++
Routine Description:
This routine services irps of minor type IRP_MN_QUERY_POWER
for the device power state
Arguments:
DeviceObject - pointer to device object
Irp - I/O request packet sent by the power manager
Return Value:
NT status value
--*/
NTSTATUS HandleDeviceQueryPower(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
NTSTATUS ntS;
DEVICE_EXTENSION * deviceExtension;
PIO_STACK_LOCATION irpStack;
DEVICE_POWER_STATE deviceState;
DPRINT(("HandleDeviceQueryPower - begins\n"));
//
// initialize variables
//
deviceExtension = (DEVICE_EXTENSION *) DeviceObject->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation(Irp);
deviceState = irpStack->Parameters.Power.State.DeviceState;
DPRINT(("Query for device power state D%X\n"
"Current device power state D%X\n",
deviceState - 1,
deviceExtension->DevPower - 1));
if(deviceExtension->WaitWakeEnable &&
deviceState > deviceExtension->DeviceCapabilities.DeviceWake) {
PoStartNextPowerIrp(Irp);
Irp->IoStatus.Status = ntS = STATUS_INVALID_DEVICE_STATE;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
DPRINT(("HandleDeviceQueryPower::"));
DevIoDecrement(deviceExtension);
return ntS;
}
if(deviceState < deviceExtension->DevPower) {
ntS = STATUS_SUCCESS;
} else {
ntS = HoldIoRequests(DeviceObject, Irp);
if(STATUS_PENDING == ntS) {
return ntS;
}
}
//
// on error complete the Irp.
// on success pass it to the lower layers
//
PoStartNextPowerIrp(Irp);
Irp->IoStatus.Status = ntS;
Irp->IoStatus.Information = 0;
if(!NT_SUCCESS(ntS)) {
IoCompleteRequest(Irp, IO_NO_INCREMENT);
} else {
IoSkipCurrentIrpStackLocation(Irp);
ntS = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
}
DPRINT(("HandleDeviceQueryPower::"));
DevIoDecrement(deviceExtension);
DPRINT(("HandleDeviceQueryPower - ends\n"));
return ntS;
}
/*********************************************************************
*
* Routine Description:
*
* This is the PoRequest - completion routine for the device power irp.
* This routine is responsible for completing the system power irp,
* received as a context.
*
* Arguments:
*
* DeviceObject - pointer to device object
* MinorFunction - minor function of the irp.
* PowerState - power state of the irp.
* Context - context passed to the completion routine.
* IoStatus - status of the device power irp.
*
* Return Value:
*
* None
*/
VOID DevPoCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction,
IN POWER_STATE PowerState, IN PVOID Context,IN PIO_STATUS_BLOCK IoStatus) {
PIRP sIrp;
DEVICE_EXTENSION * deviceExtension;
PPOWER_COMPLETION_CONTEXT powerContext;
//
// initialize variables
//
powerContext = (PPOWER_COMPLETION_CONTEXT) Context;
sIrp = powerContext->SIrp;
deviceExtension = powerContext->DeviceObject->DeviceExtension;
DPRINT(("DevPoCompletionRoutine - begins\n"));
//
// copy the D-Irp status into S-Irp
//
sIrp->IoStatus.Status = IoStatus->Status;
//
// complete the system Irp
//
PoStartNextPowerIrp(sIrp);
sIrp->IoStatus.Information = 0;
IoCompleteRequest(sIrp, IO_NO_INCREMENT);
//
// cleanup
//
DPRINT(("DevPoCompletionRoutine::"));
DevIoDecrement(deviceExtension);
ExFreePool(powerContext);
DPRINT(("DevPoCompletionRoutine - ends\n"));
}
/*********************************************************************
*
* Routine Description:
* This routine is invoked from the completion routine of the system power
* irp. This routine will PoRequest a device power irp. The system irp is
* passed as a context to the the device power irp.
*
* Arguments:
*
* DeviceObject - pointer to device object
* SIrp - system power irp.
*
* Return Value:
*
* None
*/
VOID SendDeviceIrp(IN PDEVICE_OBJECT DeviceObject,IN PIRP SIrp) {
NTSTATUS ntS;
POWER_STATE powState;
DEVICE_EXTENSION * deviceExtension;
PIO_STACK_LOCATION irpStack;
SYSTEM_POWER_STATE systemState;
DEVICE_POWER_STATE devState;
PPOWER_COMPLETION_CONTEXT powerContext;
//
// initialize variables
//
irpStack = IoGetCurrentIrpStackLocation(SIrp);
systemState = irpStack->Parameters.Power.State.SystemState;
deviceExtension = (DEVICE_EXTENSION *) DeviceObject->DeviceExtension;
DPRINT(("SendDeviceIrp - begins\n"));
//
// Read out the D-IRP out of the S->D mapping array captured in QueryCap's.
// we can choose deeper sleep states than our mapping but never choose
// lighter ones.
//
devState = deviceExtension->DeviceCapabilities.DeviceState[systemState];
powState.DeviceState = devState;
powerContext = (POWER_COMPLETION_CONTEXT*)ExAllocatePool(NonPagedPool,sizeof(POWER_COMPLETION_CONTEXT));
if(!powerContext) {
DPRINT(("Failed to alloc memory for powerContext\n"));
ntS = STATUS_INSUFFICIENT_RESOURCES;
} else {
powerContext->DeviceObject = DeviceObject;
powerContext->SIrp = SIrp;
//
// in win2k PoRequestPowerIrp can take fdo or pdo.
//
ntS = PoRequestPowerIrp(deviceExtension->PhysicalDeviceObject, irpStack->MinorFunction,
powState, (PREQUEST_POWER_COMPLETE)DevPoCompletionRoutine,powerContext, NULL);
}
if(!NT_SUCCESS(ntS)) {
if(powerContext) {
ExFreePool(powerContext);
}
PoStartNextPowerIrp(SIrp);
SIrp->IoStatus.Status = ntS;
SIrp->IoStatus.Information = 0;
IoCompleteRequest(SIrp, IO_NO_INCREMENT);
DPRINT(("SendDeviceIrp::"));
DevIoDecrement(deviceExtension);
}
DPRINT(("SendDeviceIrp - ends\n"));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -