reactos/drivers/bluetooth/fbtusb/fbtpwr.c

1064 lines
31 KiB
C

// Copyright (c) 2004, Antony C. Roberts
// Use of this file is subject to the terms
// described in the LICENSE.TXT file that
// accompanies this file.
//
// Your use of this file indicates your
// acceptance of the terms described in
// LICENSE.TXT.
//
// http://www.freebt.net
#include "fbtusb.h"
#include "fbtpwr.h"
#include "fbtpnp.h"
#include "fbtdev.h"
#include "fbtrwr.h"
#include "fbtwmi.h"
#include "fbtusr.h"
// Handle power events
NTSTATUS NTAPI FreeBT_DispatchPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PIO_STACK_LOCATION irpStack;
//PUNICODE_STRING tagString;
PDEVICE_EXTENSION deviceExtension;
irpStack = IoGetCurrentIrpStackLocation(Irp);
deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
// We don't queue power Irps, we'll only check if the
// device was removed, otherwise we'll take appropriate
// action and send it to the next lower driver. In general
// drivers should not cause long delays while handling power
// IRPs. If a driver cannot handle a power IRP in a brief time,
// it should return STATUS_PENDING and queue all incoming
// IRPs until the IRP completes.
if (Removed == deviceExtension->DeviceState)
{
// Even if a driver fails the IRP, it must nevertheless call
// PoStartNextPowerIrp to inform the Power Manager that it
// is ready to handle another power IRP.
PoStartNextPowerIrp(Irp);
Irp->IoStatus.Status = ntStatus = STATUS_DELETE_PENDING;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return ntStatus;
}
if (NotStarted == deviceExtension->DeviceState)
{
// if the device is not started yet, pass it down
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
return PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
}
FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower::"));
FreeBT_IoIncrement(deviceExtension);
switch(irpStack->MinorFunction)
{
case IRP_MN_SET_POWER:
// The Power Manager sends this IRP for one of the
// following reasons:
// 1) To notify drivers of a change to the system power state.
// 2) To change the power state of a device for which
// the Power Manager is performing idle detection.
// A driver sends IRP_MN_SET_POWER to change the power
// state of its device if it's a power policy owner for the
// device.
FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower: IRP_MN_SET_POWER\n"));
IoMarkIrpPending(Irp);
switch(irpStack->Parameters.Power.Type)
{
case SystemPowerState:
HandleSystemSetPower(DeviceObject, Irp);
ntStatus = STATUS_PENDING;
break;
case DevicePowerState:
HandleDeviceSetPower(DeviceObject, Irp);
ntStatus = STATUS_PENDING;
break;
}
break;
case IRP_MN_QUERY_POWER:
// The Power Manager sends a power IRP with the minor
// IRP code IRP_MN_QUERY_POWER to determine whether it
// can safely change to the specified system power state
// (S1-S5) and to allow drivers to prepare for such a change.
// If a driver can put its device in the requested state,
// it sets status to STATUS_SUCCESS and passes the IRP down.
FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower: IRP_MN_QUERY_POWER\n"));
IoMarkIrpPending(Irp);
switch(irpStack->Parameters.Power.Type)
{
case SystemPowerState:
HandleSystemQueryPower(DeviceObject, Irp);
ntStatus = STATUS_PENDING;
break;
case DevicePowerState:
HandleDeviceQueryPower(DeviceObject, Irp);
ntStatus = STATUS_PENDING;
break;
}
break;
case IRP_MN_WAIT_WAKE:
// The minor power IRP code IRP_MN_WAIT_WAKE provides
// for waking a device or waking the system. Drivers
// of devices that can wake themselves or the system
// send IRP_MN_WAIT_WAKE. The system sends IRP_MN_WAIT_WAKE
// only to devices that always wake the system, such as
// the power-on switch.
FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower: IRP_MN_WAIT_WAKE\n"));
IoMarkIrpPending(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(
Irp,
(PIO_COMPLETION_ROUTINE)WaitWakeCompletionRoutine,
deviceExtension,
TRUE,
TRUE,
TRUE);
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
if(!NT_SUCCESS(ntStatus))
{
FreeBT_DbgPrint(1, ("FBTUSB: Lower drivers failed the wait-wake Irp\n"));
}
ntStatus = STATUS_PENDING;
// push back the count HERE and NOT in completion routine
// a pending Wait Wake Irp should not impede stopping the device
FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower: IRP_MN_WAIT_WAKE::"));
FreeBT_IoDecrement(deviceExtension);
break;
case IRP_MN_POWER_SEQUENCE:
// A driver sends this IRP as an optimization to determine
// whether its device actually entered a specific power state.
// This IRP is optional. Power Manager cannot send this IRP.
FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower: IRP_MN_POWER_SEQUENCE\n"));
default:
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
if(!NT_SUCCESS(ntStatus))
{
FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchPower: Lower drivers failed this Irp\n"));
}
FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchPower::"));
FreeBT_IoDecrement(deviceExtension);
break;
}
return ntStatus;
}
NTSTATUS NTAPI HandleSystemQueryPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
NTSTATUS ntStatus;
PDEVICE_EXTENSION deviceExtension;
SYSTEM_POWER_STATE systemState;
PIO_STACK_LOCATION irpStack;
FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemQueryPower: Entered\n"));
// initialize variables
deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation(Irp);
systemState = irpStack->Parameters.Power.State.SystemState;
FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemQueryPower: Query for system power state S%X\n"
"FBTUSB: HandleSystemQueryPower: Current system power state S%X\n",
systemState - 1,
deviceExtension->SysPower - 1));
// Fail a query for a power state incompatible with waking up the system
if ((deviceExtension->WaitWakeEnable) && (systemState > deviceExtension->DeviceCapabilities.SystemWake))
{
FreeBT_DbgPrint(1, ("FBTUSB: HandleSystemQueryPower: Query for an incompatible system power state\n"));
PoStartNextPowerIrp(Irp);
Irp->IoStatus.Status = ntStatus = STATUS_INVALID_DEVICE_STATE;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemQueryPower::"));
FreeBT_IoDecrement(deviceExtension);
return ntStatus;
}
// if querying for a lower S-state, issue a wait-wake
if((systemState > deviceExtension->SysPower) && (deviceExtension->WaitWakeEnable))
{
IssueWaitWake(deviceExtension);
}
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(
Irp,
(PIO_COMPLETION_ROUTINE)SysPoCompletionRoutine,
deviceExtension,
TRUE,
TRUE,
TRUE);
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemQueryPower: Leaving\n"));
return STATUS_PENDING;
}
NTSTATUS NTAPI HandleSystemSetPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
NTSTATUS ntStatus;
PDEVICE_EXTENSION deviceExtension;
SYSTEM_POWER_STATE systemState;
PIO_STACK_LOCATION irpStack;
FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemSetPower: Entered\n"));
deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation(Irp);
systemState = irpStack->Parameters.Power.State.SystemState;
FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemSetPower: Set request for system power state S%X\n"
"FBTUSB: HandleSystemSetPower: Current system power state S%X\n",
systemState - 1,
deviceExtension->SysPower - 1));
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(
Irp,
(PIO_COMPLETION_ROUTINE)SysPoCompletionRoutine,
deviceExtension,
TRUE,
TRUE,
TRUE);
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
FreeBT_DbgPrint(3, ("FBTUSB: HandleSystemSetPower: Leaving\n"));
return STATUS_PENDING;
}
NTSTATUS NTAPI HandleDeviceQueryPower(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS ntStatus;
PDEVICE_EXTENSION deviceExtension;
PIO_STACK_LOCATION irpStack;
DEVICE_POWER_STATE deviceState;
FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceQueryPower: Entered\n"));
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation(Irp);
deviceState = irpStack->Parameters.Power.State.DeviceState;
FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceQueryPower: Query for device power state D%X\n"
"FBTUSB: HandleDeviceQueryPower: Current device power state D%X\n",
deviceState - 1,
deviceExtension->DevPower - 1));
if (deviceExtension->WaitWakeEnable && deviceState > deviceExtension->DeviceCapabilities.DeviceWake)
{
PoStartNextPowerIrp(Irp);
Irp->IoStatus.Status = ntStatus = STATUS_INVALID_DEVICE_STATE;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceQueryPower::"));
FreeBT_IoDecrement(deviceExtension);
return ntStatus;
}
if (deviceState < deviceExtension->DevPower)
{
ntStatus = STATUS_SUCCESS;
}
else
{
ntStatus = HoldIoRequests(DeviceObject, Irp);
if(STATUS_PENDING == ntStatus)
{
return ntStatus;
}
}
// on error complete the Irp.
// on success pass it to the lower layers
PoStartNextPowerIrp(Irp);
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
if(!NT_SUCCESS(ntStatus))
{
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
else
{
IoSkipCurrentIrpStackLocation(Irp);
ntStatus=PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
}
FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceQueryPower::"));
FreeBT_IoDecrement(deviceExtension);
FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceQueryPower: Leaving\n"));
return ntStatus;
}
NTSTATUS NTAPI SysPoCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
{
NTSTATUS ntStatus;
PIO_STACK_LOCATION irpStack;
ntStatus = Irp->IoStatus.Status;
irpStack = IoGetCurrentIrpStackLocation(Irp);
FreeBT_DbgPrint(3, ("FBTUSB: SysPoCompletionRoutine: Entered\n"));
// lower drivers failed this Irp
if(!NT_SUCCESS(ntStatus))
{
PoStartNextPowerIrp(Irp);
FreeBT_DbgPrint(3, ("FBTUSB: SysPoCompletionRoutine::"));
FreeBT_IoDecrement(DeviceExtension);
return STATUS_SUCCESS;
}
// ..otherwise update the cached system power state (IRP_MN_SET_POWER)
if(irpStack->MinorFunction == IRP_MN_SET_POWER)
{
DeviceExtension->SysPower = irpStack->Parameters.Power.State.SystemState;
}
// queue device irp and return STATUS_MORE_PROCESSING_REQUIRED
SendDeviceIrp(DeviceObject, Irp);
FreeBT_DbgPrint(3, ("FBTUSB: SysPoCompletionRoutine: Leaving\n"));
return STATUS_MORE_PROCESSING_REQUIRED;
}
VOID NTAPI SendDeviceIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP SIrp )
{
NTSTATUS ntStatus;
POWER_STATE powState;
PDEVICE_EXTENSION deviceExtension;
PIO_STACK_LOCATION irpStack;
SYSTEM_POWER_STATE systemState;
DEVICE_POWER_STATE devState;
PPOWER_COMPLETION_CONTEXT powerContext;
irpStack = IoGetCurrentIrpStackLocation(SIrp);
systemState = irpStack->Parameters.Power.State.SystemState;
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
FreeBT_DbgPrint(3, ("FBTUSB: SendDeviceIrp: Entered\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 = (PPOWER_COMPLETION_CONTEXT) ExAllocatePool(NonPagedPool, sizeof(POWER_COMPLETION_CONTEXT));
if (!powerContext)
{
FreeBT_DbgPrint(1, ("FBTUSB: SendDeviceIrp: Failed to alloc memory for powerContext\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
else
{
powerContext->DeviceObject = DeviceObject;
powerContext->SIrp = SIrp;
// in win2k PoRequestPowerIrp can take fdo or pdo.
ntStatus = PoRequestPowerIrp(
deviceExtension->PhysicalDeviceObject,
irpStack->MinorFunction,
powState,
(PREQUEST_POWER_COMPLETE)DevPoCompletionRoutine,
powerContext,
NULL);
}
if (!NT_SUCCESS(ntStatus))
{
if (powerContext)
{
ExFreePool(powerContext);
}
PoStartNextPowerIrp(SIrp);
SIrp->IoStatus.Status = ntStatus;
SIrp->IoStatus.Information = 0;
IoCompleteRequest(SIrp, IO_NO_INCREMENT);
FreeBT_DbgPrint(3, ("FBTUSB: SendDeviceIrp::"));
FreeBT_IoDecrement(deviceExtension);
}
FreeBT_DbgPrint(3, ("FBTUSB: SendDeviceIrp: Leaving\n"));
}
VOID NTAPI DevPoCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
{
PIRP sIrp;
PDEVICE_EXTENSION deviceExtension;
PPOWER_COMPLETION_CONTEXT powerContext;
powerContext = (PPOWER_COMPLETION_CONTEXT) Context;
sIrp = powerContext->SIrp;
deviceExtension = (PDEVICE_EXTENSION) powerContext->DeviceObject->DeviceExtension;
FreeBT_DbgPrint(3, ("FBTUSB: DevPoCompletionRoutine: Entered\n"));
sIrp->IoStatus.Status = IoStatus->Status;
PoStartNextPowerIrp(sIrp);
sIrp->IoStatus.Information = 0;
IoCompleteRequest(sIrp, IO_NO_INCREMENT);
FreeBT_DbgPrint(3, ("FBTUSB: DevPoCompletionRoutine::"));
FreeBT_IoDecrement(deviceExtension);
ExFreePool(powerContext);
FreeBT_DbgPrint(3, ("FBTUSB: DevPoCompletionRoutine: Leaving\n"));
}
NTSTATUS NTAPI HandleDeviceSetPower(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
KIRQL oldIrql;
NTSTATUS ntStatus;
POWER_STATE newState;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
DEVICE_POWER_STATE newDevState,
oldDevState;
FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: Entered\n"));
deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation(Irp);
oldDevState = deviceExtension->DevPower;
newState = irpStack->Parameters.Power.State;
newDevState = newState.DeviceState;
FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: Set request for device power state D%X\n"
"FBTUSB: HandleDeviceSetPower: Current device power state D%X\n",
newDevState - 1,
deviceExtension->DevPower - 1));
if (newDevState < oldDevState)
{
FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: Adding power to the device\n"));
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(
Irp,
(PIO_COMPLETION_ROUTINE)FinishDevPoUpIrp,
deviceExtension,
TRUE,
TRUE,
TRUE);
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
}
else
{
// newDevState >= oldDevState
// hold I/O if transition from D0 -> DX (X = 1, 2, 3)
// if transition from D1 or D2 to deeper sleep states,
// I/O queue is already on hold.
if(PowerDeviceD0 == oldDevState && newDevState > oldDevState)
{
// D0 -> DX transition
FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: Removing power from the device\n"));
ntStatus = HoldIoRequests(DeviceObject, Irp);
if (!NT_SUCCESS(ntStatus))
{
PoStartNextPowerIrp(Irp);
Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower::"));
FreeBT_IoDecrement(deviceExtension);
return ntStatus;
}
else
{
goto HandleDeviceSetPower_Exit;
}
}
else if (PowerDeviceD0 == oldDevState && PowerDeviceD0 == newDevState)
{
// D0 -> D0
// unblock the queue which may have been blocked processing
// query irp
FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: A SetD0 request\n"));
KeAcquireSpinLock(&deviceExtension->DevStateLock, &oldIrql);
deviceExtension->QueueState = AllowRequests;
KeReleaseSpinLock(&deviceExtension->DevStateLock, oldIrql);
ProcessQueuedRequests(deviceExtension);
}
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(
Irp,
(PIO_COMPLETION_ROUTINE) FinishDevPoDnIrp,
deviceExtension,
TRUE,
TRUE,
TRUE);
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
if(!NT_SUCCESS(ntStatus))
{
FreeBT_DbgPrint(1, ("FBTUSB: HandleDeviceSetPower: Lower drivers failed a power Irp\n"));
}
}
HandleDeviceSetPower_Exit:
FreeBT_DbgPrint(3, ("FBTUSB: HandleDeviceSetPower: Leaving\n"));
return STATUS_PENDING;
}
NTSTATUS NTAPI FinishDevPoUpIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
{
NTSTATUS ntStatus;
FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoUpIrp: Entered\n"));
ntStatus = Irp->IoStatus.Status;
if(Irp->PendingReturned)
{
IoMarkIrpPending(Irp);
}
if(!NT_SUCCESS(ntStatus))
{
PoStartNextPowerIrp(Irp);
FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoUpIrp::"));
FreeBT_IoDecrement(DeviceExtension);
return STATUS_SUCCESS;
}
SetDeviceFunctional(DeviceObject, Irp, DeviceExtension);
FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoUpIrp: Leaving\n"));
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS NTAPI SetDeviceFunctional(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
{
KIRQL oldIrql;
NTSTATUS ntStatus;
POWER_STATE newState;
PIO_STACK_LOCATION irpStack;
DEVICE_POWER_STATE newDevState, oldDevState;
ntStatus = Irp->IoStatus.Status;
irpStack = IoGetCurrentIrpStackLocation(Irp);
newState = irpStack->Parameters.Power.State;
newDevState = newState.DeviceState;
oldDevState = DeviceExtension->DevPower;
FreeBT_DbgPrint(3, ("FBTUSB: SetDeviceFunctional: Entered\n"));
// update the cached state
DeviceExtension->DevPower = newDevState;
// restore appropriate amount of state to our h/w
// this driver does not implement partial context
// save/restore.
PoSetPowerState(DeviceObject, DevicePowerState, newState);
if(PowerDeviceD0 == newDevState)
{
KeAcquireSpinLock(&DeviceExtension->DevStateLock, &oldIrql);
DeviceExtension->QueueState = AllowRequests;
KeReleaseSpinLock(&DeviceExtension->DevStateLock, oldIrql);
ProcessQueuedRequests(DeviceExtension);
}
PoStartNextPowerIrp(Irp);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
FreeBT_DbgPrint(3, ("FBTUSB: SetDeviceFunctional::"));
FreeBT_IoDecrement(DeviceExtension);
FreeBT_DbgPrint(3, ("FBTUSB: SetDeviceFunctional: Leaving\n"));
return STATUS_SUCCESS;
}
NTSTATUS NTAPI FinishDevPoDnIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
{
NTSTATUS ntStatus;
POWER_STATE newState;
PIO_STACK_LOCATION irpStack;
FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoDnIrp: Entered\n"));
ntStatus = Irp->IoStatus.Status;
irpStack = IoGetCurrentIrpStackLocation(Irp);
newState = irpStack->Parameters.Power.State;
if (NT_SUCCESS(ntStatus) && irpStack->MinorFunction == IRP_MN_SET_POWER)
{
FreeBT_DbgPrint(3, ("FBTUSB: updating cache..\n"));
DeviceExtension->DevPower = newState.DeviceState;
PoSetPowerState(DeviceObject, DevicePowerState, newState);
}
PoStartNextPowerIrp(Irp);
FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoDnIrp::"));
FreeBT_IoDecrement(DeviceExtension);
FreeBT_DbgPrint(3, ("FBTUSB: FinishDevPoDnIrp: Leaving\n"));
return STATUS_SUCCESS;
}
NTSTATUS NTAPI HoldIoRequests(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
NTSTATUS ntStatus;
PIO_WORKITEM item;
PDEVICE_EXTENSION deviceExtension;
PWORKER_THREAD_CONTEXT context;
FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequests: Entered\n"));
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
deviceExtension->QueueState = HoldRequests;
context = (PWORKER_THREAD_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);
ntStatus = STATUS_PENDING;
}
else
{
FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequests: Failed to allocate memory for workitem\n"));
ExFreePool(context);
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
else
{
FreeBT_DbgPrint(1, ("FBTUSB: HoldIoRequests: Failed to alloc memory for worker thread context\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequests: Leaving\n"));
return ntStatus;
}
VOID NTAPI HoldIoRequestsWorkerRoutine(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context)
{
PIRP irp;
NTSTATUS ntStatus;
PDEVICE_EXTENSION deviceExtension;
PWORKER_THREAD_CONTEXT context;
FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine: Entered\n"));
deviceExtension = (PDEVICE_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 FreeBT_IoDecrement twice: once each for the S-Irp and D-Irp.
FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine::"));
FreeBT_IoDecrement(deviceExtension);
FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine::"));
FreeBT_IoDecrement(deviceExtension);
KeWaitForSingleObject(&deviceExtension->StopEvent, Executive, KernelMode, FALSE, NULL);
// Increment twice to restore the count
FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine::"));
FreeBT_IoIncrement(deviceExtension);
FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine::"));
FreeBT_IoIncrement(deviceExtension);
// now send the Irp down
IoCopyCurrentIrpStackLocationToNext(irp);
IoSetCompletionRoutine(
irp,
(PIO_COMPLETION_ROUTINE) FinishDevPoDnIrp,
deviceExtension,
TRUE,
TRUE,
TRUE);
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, irp);
if(!NT_SUCCESS(ntStatus))
{
FreeBT_DbgPrint(1, ("FBTUSB: HoldIoRequestsWorkerRoutine: Lower driver fail a power Irp\n"));
}
IoFreeWorkItem(context->WorkItem);
ExFreePool((PVOID)context);
FreeBT_DbgPrint(3, ("FBTUSB: HoldIoRequestsWorkerRoutine: Leaving\n"));
}
NTSTATUS NTAPI QueueRequest(IN OUT PDEVICE_EXTENSION DeviceExtension, IN PIRP Irp)
{
KIRQL oldIrql;
NTSTATUS ntStatus;
FreeBT_DbgPrint(3, ("FBTUSB: QueueRequests: Entered\n"));
ntStatus = STATUS_PENDING;
ASSERT(HoldRequests == DeviceExtension->QueueState);
KeAcquireSpinLock(&DeviceExtension->QueueLock, &oldIrql);
InsertTailList(&DeviceExtension->NewRequestsQueue, &Irp->Tail.Overlay.ListEntry);
IoMarkIrpPending(Irp);
IoSetCancelRoutine(Irp, CancelQueued);
KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
FreeBT_DbgPrint(3, ("FBTUSB: QueueRequests: Leaving\n"));
return ntStatus;
}
VOID NTAPI CancelQueued(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PDEVICE_EXTENSION deviceExtension;
KIRQL oldIrql;
FreeBT_DbgPrint(3, ("FBTUSB: CancelQueued: Entered\n"));
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
oldIrql = Irp->CancelIrql;
// Release the cancel spin lock
IoReleaseCancelSpinLock(Irp->CancelIrql);
// Acquire the queue lock
KeAcquireSpinLockAtDpcLevel(&deviceExtension->QueueLock);
// Remove the cancelled Irp from queue and release the lock
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
KeReleaseSpinLock(&deviceExtension->QueueLock, oldIrql);
// complete with STATUS_CANCELLED
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
FreeBT_DbgPrint(3, ("FBTUSB: CancelQueued: Leaving\n"));
return;
}
NTSTATUS NTAPI IssueWaitWake(IN PDEVICE_EXTENSION DeviceExtension)
{
POWER_STATE poState;
NTSTATUS ntStatus;
FreeBT_DbgPrint(3, ("FBTUSB: IssueWaitWake: Entered\n"));
if(InterlockedExchange(&DeviceExtension->FlagWWOutstanding, 1))
{
return STATUS_DEVICE_BUSY;
}
InterlockedExchange(&DeviceExtension->FlagWWCancel, 0);
// lowest state from which this Irp will wake the system
poState.SystemState = DeviceExtension->DeviceCapabilities.SystemWake;
ntStatus = PoRequestPowerIrp(DeviceExtension->PhysicalDeviceObject,
IRP_MN_WAIT_WAKE,
poState,
(PREQUEST_POWER_COMPLETE) WaitWakeCallback,
DeviceExtension,
&DeviceExtension->WaitWakeIrp);
if(!NT_SUCCESS(ntStatus))
{
InterlockedExchange(&DeviceExtension->FlagWWOutstanding, 0);
}
FreeBT_DbgPrint(3, ("FBTUSB: IssueWaitWake: Leaving\n"));
return ntStatus;
}
VOID NTAPI CancelWaitWake(IN PDEVICE_EXTENSION DeviceExtension)
{
PIRP Irp;
FreeBT_DbgPrint(3, ("FBTUSB: CancelWaitWake: Entered\n"));
Irp = (PIRP) InterlockedExchangePointer((PVOID*)&DeviceExtension->WaitWakeIrp,
NULL);
if(Irp)
{
IoCancelIrp(Irp);
if(InterlockedExchange(&DeviceExtension->FlagWWCancel, 1))
{
PoStartNextPowerIrp(Irp);
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
}
FreeBT_DbgPrint(3, ("FBTUSB: CancelWaitWake: Leaving\n"));
}
NTSTATUS NTAPI WaitWakeCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PDEVICE_EXTENSION DeviceExtension)
{
FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCompletionRoutine: Entered\n"));
if(Irp->PendingReturned)
{
IoMarkIrpPending(Irp);
}
// Nullify the WaitWakeIrp pointer-the Irp is released
// as part of the completion process. If it's already NULL,
// avoid race with the CancelWaitWake routine.
if(InterlockedExchangePointer((PVOID*)&DeviceExtension->WaitWakeIrp, NULL))
{
PoStartNextPowerIrp(Irp);
return STATUS_SUCCESS;
}
// CancelWaitWake has run.
// If FlagWWCancel != 0, complete the Irp.
// If FlagWWCancel == 0, CancelWaitWake completes it.
if(InterlockedExchange(&DeviceExtension->FlagWWCancel, 1))
{
PoStartNextPowerIrp(Irp);
return STATUS_CANCELLED;
}
FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCompletionRoutine: Leaving\n"));
return STATUS_MORE_PROCESSING_REQUIRED;
}
VOID NTAPI WaitWakeCallback(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus)
{
NTSTATUS ntStatus;
POWER_STATE powerState;
PDEVICE_EXTENSION deviceExtension;
FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCallback: Entered\n"));
deviceExtension = (PDEVICE_EXTENSION) Context;
InterlockedExchange(&deviceExtension->FlagWWOutstanding, 0);
if(!NT_SUCCESS(IoStatus->Status))
{
return;
}
// wake up the device
if(deviceExtension->DevPower == PowerDeviceD0)
{
FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCallback: Device already powered up...\n"));
return;
}
FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCallback::"));
FreeBT_IoIncrement(deviceExtension);
powerState.DeviceState = PowerDeviceD0;
ntStatus = PoRequestPowerIrp(deviceExtension->PhysicalDeviceObject,
IRP_MN_SET_POWER,
powerState,
(PREQUEST_POWER_COMPLETE) WWIrpCompletionFunc,
deviceExtension,
NULL);
if(deviceExtension->WaitWakeEnable)
{
IssueWaitWake(deviceExtension);
}
FreeBT_DbgPrint(3, ("FBTUSB: WaitWakeCallback: Leaving\n"));
return;
}
PCHAR NTAPI PowerMinorFunctionString (IN UCHAR MinorFunction)
{
switch (MinorFunction)
{
case IRP_MN_SET_POWER:
return "IRP_MN_SET_POWER\n";
case IRP_MN_QUERY_POWER:
return "IRP_MN_QUERY_POWER\n";
case IRP_MN_POWER_SEQUENCE:
return "IRP_MN_POWER_SEQUENCE\n";
case IRP_MN_WAIT_WAKE:
return "IRP_MN_WAIT_WAKE\n";
default:
return "IRP_MN_?????\n";
}
}