www.pudn.com > usbfx2lk_v1.1.zip > usbfx2lk_power.cpp
///////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright 2005 OSR Open Systems Resources, Inc.
// Copyright (c) 2000 Microsoft Corporation
// All Rights Reserved
//
// This sofware is supplied for instructional purposes only.
//
// OSR Open Systems Resources, Inc. (OSR) expressly disclaims any warranty
// for this software. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
// THE IMPLIED WARRANTIES OF MECHANTABILITY OR FITNESS FOR A PARTICULAR
// PURPOSE. THE ENTIRE RISK ARISING FROM THE USE OF THIS SOFTWARE REMAINS
// WITH YOU. OSR's entire liability and your exclusive remedy shall not
// exceed the price paid for this material. In no event shall OSR or its
// suppliers be liable for any damages whatsoever (including, without
// limitation, damages for loss of business profit, business interruption,
// loss of business information, or any other pecuniary loss) arising out
// of the use or inability to use this software, even if OSR has been
// advised of the possibility of such damages. Because some states/
// jurisdictions do not allow the exclusion or limitation of liability for
// consequential or incidental damages, the above limitation may not apply
// to you.
//
// OSR Open Systems Resources, Inc.
// 105 Route 101A Suite 19
// Amherst, NH 03031 (603) 595-6500 FAX: (603) 595-6503
// email bugs to: bugs@osr.com
//
//
// MODULE:
//
// USBFx2LK_Power.cpp
//
// ABSTRACT:
//
// This file contains the routines that handle IRP_MJ_POWER processing for the
// OSR USB FX2 Learning Kit Device
//
// AUTHOR(S):
//
// OSR Open Systems Resources, Inc.
//
///////////////////////////////////////////////////////////////////////////////
#include "usbfx2lk.h"
#ifdef WPP_TRACING
//
// Include the necessary tmh file - this is
// just a matter of course if you're using WPP tracing.
//
extern "C" {
#include "usbfx2lk_power.tmh"
}
#endif
//
// Forward Declarations
//
NTSTATUS OsrHandleSystemPowerIrp(PDEVICE_OBJECT DeviceObject,PIRP Irp);
NTSTATUS SystemPowerIoCompletionRoutine(PDEVICE_OBJECT DeviceObject,PIRP Irp,
PVOID Context);
NTSTATUS OsrHandleDevicePowerIrp(PDEVICE_OBJECT DeviceObject,PIRP Irp);
NTSTATUS DevicePowerIoCompletionRoutine(PDEVICE_OBJECT DeviceObject,PIRP Irp,
PVOID Context);
VOID DevicePowerRequestCompletionRoutine(PDEVICE_OBJECT DeviceObject,UCHAR MinorFunction,
POWER_STATE PowerState,PVOID Context,PIO_STATUS_BLOCK IoStatus);
VOID WaitWakeIrpCompletionFunc(PDEVICE_OBJECT DeviceObject,UCHAR MinorFunction,
POWER_STATE PowerState,PVOID Context,PIO_STATUS_BLOCK IoStatus);
VOID WaitWakeCallback(PDEVICE_OBJECT DeviceObject,UCHAR MinorFunction,POWER_STATE PowerState,
PVOID Context,PIO_STATUS_BLOCK IoStatus);
NTSTATUS WaitWakeCompletionRoutine(PDEVICE_OBJECT DeviceObject,PIRP Irp,PUSBFX2LK_EXT DevExt);
///////////////////////////////////////////////////////////////////////////////
//
// UsbFx2LkPower
//
// This routine is called by the IO Manager to process a IRP_MJ_POWER
// Irp.
//
//
// INPUTS:
//
// DeviceObject - One of our Device Objects.
// Irp - The Irp to process.
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// User Context
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS UsbFx2LkPower(PDEVICE_OBJECT DeviceObject,PIRP Irp)
{
PUSBFX2LK_EXT devExt = (PUSBFX2LK_EXT)DeviceObject->DeviceExtension;
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
POWER_STATE_TYPE powerType;
NTSTATUS status;
KIRQL oldIrql;
//
// We're guaranteed to be called here at IRQL PASSIVE_LEVEL
//
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
//
// Increment the count of Outstanding IOs
//
OsrIncrementOutstandingIoCount(devExt,__FILE__,__LINE__);
if (ioStack->MinorFunction <= IRP_MN_QUERY_POWER) {
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO,
("OsrPower: Entered with Minor Function %s\n",
OsrMinorFunctionToString(ioStack->MajorFunction,
ioStack->MinorFunction)));
} else {
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO,
("OsrPower: Entered with unusual Minor Function 0x%x\n",
ioStack->MinorFunction));
}
//
// See what sort of state we're in. For our power policy, we have
// decided that we will not accept any power requests if we are not
// in STATE_STARTED.
//
// Why? Because as far as we can tell, it doesn't make any SENSE to handle
// them in any other state. If we're in REMOVE_PENDING and we process
// a power down, what do we do if we get a IRP_MN_CANCEL_REMOVE? Or, if
// we're in STOPPED we've already given up our resources so how
// do we tell our device to power down? In SURPRISE_REMOVED, what
// hardware are we going to power down??
//
KeAcquireSpinLock(&devExt->IoStateLock,&oldIrql);
if (devExt->DevicePnPState != STATE_STARTED &&
devExt->DevicePnPState != STATE_POWER_PROCESSING) {
KeReleaseSpinLock(&devExt->IoStateLock,oldIrql);
//
// We ALWAYS need to tell the system to start the next
// power IRP before we exit. Yes, even if we're failing
// the current request.
//
PoStartNextPowerIrp(Irp);
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
Irp->IoStatus.Information = 0;
//
// Complete the request here, without passing it down...
//
IoCompleteRequest(Irp, IO_NO_INCREMENT);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_POWER_INFO,
("OsrPower: Failing Power request due to Pnp State! Current PnP state - %s\n",
OsrPrintState(devExt)));
//
// We're done with this request
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_POWER_INFO, ("OsrPower: Exiting...\n"));
return STATUS_INVALID_DEVICE_STATE;
}
KeReleaseSpinLock(&devExt->IoStateLock,oldIrql);
//
// Is this a system power Irp or a device power Irp?
//
powerType = ioStack->Parameters.Power.Type;
switch (powerType) {
case SystemPowerState:
//
// Transfer control to our SYSTEM power IRP routine...
//
status = OsrHandleSystemPowerIrp(DeviceObject, Irp);
//
// Don't release our remove lock!
//
break;
case DevicePowerState:
//
// Transfer control to our DEVICE power IRP routine...
//
status = OsrHandleDevicePowerIrp(DeviceObject, Irp);
//
// Don't release our remove lock!
//
break;
default:
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_POWER_INFO,
("OsrPower: Not a device or system power request!?! Pass it along...\n"));
//
// Call PoStartNextPowerIrp to indicate that we're done
// processing this power IRP
//
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
//
// Pass the IRP down using PoCallDriver
//
status = PoCallDriver(devExt->DeviceToSendIrpsTo, Irp);
//
// We're done with this request
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
break;
}
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("OsrPower: Exiting...\n"));
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrHandleSystemPowerIrp
//
// Entry point to handle SYSTEM power IRPs
//
// INPUTS:
//
// DeviceObject - Pointer to our device object.
// Irp - Address of the system power IRP.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// STATUS_PENDING if we are going to handle the IRP,
// otherwise the NTSTATUS value of the driver below us
//
// IRQL:
//
// This routine is called at IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// This routine is called in an arbitrary thread context
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS OsrHandleSystemPowerIrp(PDEVICE_OBJECT DeviceObject,PIRP Irp)
{
PUSBFX2LK_EXT devExt = (PUSBFX2LK_EXT)DeviceObject->DeviceExtension;
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
POWER_STATE powerState;
NTSTATUS status;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("OsrHandleSystemPowerIrp: Entered...\n"));
//
// Which power state are we talking about?
//
powerState = ioStack->Parameters.Power.State;
//
// For ALL power IRPs, we are REQUIRED to:
//
// 1) call PoStartNextPowerIrp()
// 2) Pass the IRP down to the next lower driver, unless
// we complete the request with an error.
//
switch(ioStack->MinorFunction) {
case IRP_MN_QUERY_POWER:
//
// The code below assumes that this device is the power
// policy owner. This is the norm for most FDO devices.
//
//
// There's a slightly annoying and unexpected side effect
// of being suspended while processing the S Query IRP.
//
// If we're going to a power state that is lower than
// what our device can wake the system from, the bus
// driver will allow the system suspend to the lower,
// unwakeable state. This means that the system will
// suspend, we'll have a Wait Wake IRP pending, but
// nothing we do will wake the system. However, if
// our device is powered up when we handle the S-IRP,
// then the bus driver will "do the right thing" and
// fail the S-IRP query for the power down. This will
// result in a new S-IRP coming in, hopefully with an
// S state that we can suspend from.
//
SSPowerDeviceIfSuspended(devExt);
//
// if this device is something like an industrial device,
// that will typically be used in an industrial or other
// fixed setting, then it may be desireable to avoid power
// downs while I/O requests are in progress. In this case
// the driver should keep some device state to indicate it is
// busy. For example this could be done by tracking open
// handles to the device. If the device is determined to be
// busy, the query to power down should be rejected. Something
// like following commented-out code could be used in this case.
//
//
//If(deviceBusy) {
// PoStartNextPowerIrp(Irp);
//
// Irp->IoStatus.Information = 0;
// Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
//
// //
// // Complete the request here, without passing it down...
// //
//
// IoCompleteRequest (Irp, IO_NO_INCREMENT);
//
// return STATUS_DEVICE_BUSY;
//}
//
// If the system is powering DOWN (numerically higher S-states
// are lower in power) and we support wait wake, submit
// a wait wake request
//
if((powerState.SystemState > devExt->SystemPowerState) && (devExt->WaitWakeEnable)) {
IssueWaitWake(devExt);
}
//
// Unless it's absolutely mission critical, you should agree
// to the request to power down your device. If one device
// on the system rejects the request, things could get ugly
// and the system might not properly shutdown in a timely
// manner (or even worse, not at all...).
//
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_POWER_INFO,
("OsrHandleSystemPowerIrp: Querying for System state transition to %s\n",
OsrPrintSystemPowerState(powerState.SystemState)));
//
// mark the IRP pending
//
IoMarkIrpPending(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
//
// Insert our completion routine into the system power IRP.
//
IoSetCompletionRoutine(Irp,
SystemPowerIoCompletionRoutine,
devExt,
TRUE,
TRUE,
TRUE);
//
// Pass the system power irp down using PoCallDriver!
// It is an error to use IoCallDriver here...Power irps
// must be passed down with PoCallDriver, because it
// will do some additional work to ensure proper
// synchronization of power Irps
//
(VOID)PoCallDriver(devExt->DeviceToSendIrpsTo,
Irp);
//
// We've registered an IO completion routine so we're not
// finished with this Irp...DON'T release our remove lock!
//
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("OsrHandleSystemPowerIrp: Exiting!\n"));
//
// The IRP is marked pending so we MUST return STATUS_PENDING here.
//
return STATUS_PENDING;
case IRP_MN_SET_POWER:
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_POWER_INFO,
("OsrHandleSystemPowerIrp: Setting System state to %s\n",
OsrPrintSystemPowerState(powerState.SystemState)));
//
// mark the IRP pending
//
IoMarkIrpPending(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
//
// Set our completion routine into the system power IRP
//
IoSetCompletionRoutine(Irp,
SystemPowerIoCompletionRoutine,
(PVOID)devExt,
TRUE,
TRUE,
TRUE);
//
// Pass the irp down using PoCallDriver! It is an
// error to use IoCallDriver here...Power irps
// must be passed down with PoCallDriver, since it
// will do some additional work to ensure proper
// synchronization of power Irps
//
(VOID)PoCallDriver(devExt->DeviceToSendIrpsTo,
Irp);
//
// We've registered an IO completion routine so we're not
// finished with this Irp...DON'T release our remove lock!
//
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("OsrHandleSystemPowerIrp: Exiting!\n"));
//
// The IRP is marked pending so we
// MUST return STATUS_PENDING here.
//
return STATUS_PENDING;
case IRP_MN_WAIT_WAKE:
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_POWER_INFO,
("OsrHandleSystemPowerIrp: IRP_MN_WAIT_WAKE Received\n"));
IoMarkIrpPending(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(
Irp,
(PIO_COMPLETION_ROUTINE)WaitWakeCompletionRoutine,
devExt,
TRUE,
TRUE,
TRUE);
PoStartNextPowerIrp(Irp);
status = PoCallDriver(devExt->DeviceToSendIrpsTo, Irp);
if(!NT_SUCCESS(status)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_POWER_INFO,("Lower drivers failed the wait-wake Irp\n"));
}
status = STATUS_PENDING;
//
// push back the count HERE and NOT in completion routine
// a pending Wait Wake Irp should not impede stopping the device
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("OsrHandleSystemPowerIrp: Exit.\n"));
return STATUS_PENDING;
case IRP_MN_BOGUS:
//
// Driver Verifier bogus minor function code
//
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_POWER_INFO,
("OsrHandleSystemPowerIrp: Received IRP_MN_BOGUS: Just pass it along...\n"));
//
// Fall through...
//
case IRP_MN_POWER_SEQUENCE:
//
// This device does not support wake or power sequence so
// we just send the request down to the bus
//
//
// Fall through...
//
default:
//
// Unknown power code...
//
//
// No matter what we always must call
// PoStartNextPowerIrp...
//
// We must also always make this call BEFORE calling
// IoSkipCurrentIrpStackLocation. Why? Because
// PoStartNextPowerIrp lets another power Irp of
// the same kind that we're processing now through
// (System or Device). How does it know what kind
// of Irp we're handling? Why from the current
// stack location of course!
//
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
//
// Pass the irp down using PoCallDriver! It is an
// error to use IoCallDriver here...Power irps
// must be passed down with PoCallDriver, since it
// will do some additional work to ensure proper
// synchronization of power Irps
//
status = PoCallDriver(devExt->DeviceToSendIrpsTo, Irp);
//
// We're done with this request
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("OsrHandleSystemPowerIrp: Exiting!\n"));
return status;
}
//
// We never get here...
//
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_POWER_INFO,
("OsrHandleSystemPowerIrp: Should never reach the end! Breaking into the debugger if attached...\n"));
//
// Use KdBreakPoint instead of DbgBreakPoint so that
// we only break in the checked build...
//
KdBreakPoint();
return STATUS_UNSUCCESSFUL;
}
///////////////////////////////////////////////////////////////////////////////
//
// SystemPowerIoCompletionRoutine
//
// Our I/O completion routine for system QUERY_POWER and SET_POWER IRPs.
//
// INPUTS:
//
// DeviceObject - Pointer to device object.
// Irp - Address of the system power IRP.
// Context - the device extension
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// NTSTATUS value signaling the I/O manager to continue processing IRP
// stack locations or not.
//
// IRQL:
//
// This routine is called at IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// This routine is called in an arbitrary thread context
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS SystemPowerIoCompletionRoutine(PDEVICE_OBJECT DeviceObject,PIRP Irp,PVOID Context)
{
PUSBFX2LK_EXT devExt = (PUSBFX2LK_EXT) Context;
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status;
POWER_STATE powerState;
SYSTEM_POWER_STATE newSystemPowerState = ioStack->Parameters.Power.State.SystemState;
UCHAR minorFunction = ioStack->MinorFunction;
UNREFERENCED_PARAMETER(DeviceObject);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("SystemPowerIoCompletionRoutine: Entered...\n"));
//
// No need to propagate the pending flag here as
// we already marked the IRP pending in the power
// dispatch routine
//
//
// If the system power IRP failed for any reason, there is
// no reason to go on and request the device power IRP.
//
status = Irp->IoStatus.Status;
if(!NT_SUCCESS(status)) {
//
// Let the power manager know we are ready to handle
// the next SystemPowerState power IRP.
//
PoStartNextPowerIrp(Irp);
//
// We're done with this request.
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_POWER_INFO,
("SystemPowerIoCompletionRoutine: System Power Irp failed with status 0x%8.8x (%s)!\n",
status, OsrNtStatusToString(status)));
//
// Stop processing by returning STATUS_SUCCESS (
// it would be nice to return an error here,
// but completion routines must return either
// STATUS_SUCCESS or STATUS_MORE_PROCESSING_REQUIRED...
//
return STATUS_SUCCESS;
}
//
// Save the system power IRP in the device context to
// be completed after the device power IRP, that we request,
// has been processed by the entire stack.
//
devExt->SystemPowerIrp = Irp;
//
// As the power policy owner we have to perform
// the system power state to device power state mappings.
// We received default mappings from the bus driver by
// catching the DEVICE_CAPABILITIES stucture in the PnP
// QUERY_CAPABILITIES request on its way up from the PDO.
// We use what the bus gave us here unmolested.
//
powerState.DeviceState =
devExt->SystemToDevicePowerMappings[ioStack->Parameters.Power.State.SystemState];
//
// Now we request the device power IRP.
//
status = PoRequestPowerIrp(devExt->PhysicalDeviceObject,
ioStack->MinorFunction,
powerState,
DevicePowerRequestCompletionRoutine,
(PVOID)devExt,
NULL);
//
// PoRequestPowerIrp returns STATUS_PENDING on success...
//
if (status != STATUS_PENDING) {
//
// We're here either because there were insufficient
// resources available to allocate the power irp
// or the minor function supplied as parameter two
// was invalid. Nothing much we can do but return...
//
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_POWER_INFO,
("SystemPowerIoCompletionRoutine: Unable to allocate device power Irp! Status 0x%8.8x (%s)\n",
status, OsrNtStatusToString(status)));
//
// We need to allow the next power Irp to start...
//
PoStartNextPowerIrp(devExt->SystemPowerIrp);
//
// Fill in the Irp with the failure status...
//
devExt->SystemPowerIrp->IoStatus.Status = status;
devExt->SystemPowerIrp = NULL;
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_POWER_INFO, ("SystemPowerIoCompletionRoutine: Exiting!\n"));
//
// We don't have an Irp to reclaim so just return
// success to continue completion processing...
//
return STATUS_SUCCESS;
}
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_POWER_INFO, ("SystemPowerIoCompletionRoutine: Exiting!\n"));
if(minorFunction == IRP_MN_SET_POWER) {
devExt->SystemPowerState = newSystemPowerState;
}
//
// We complete the system power IRP in the power completion routine. The
// power completion routine, not to be confused with an I/O completion routine,
// is called when the device power IRP, requested above, has been processed by
// every device in the stack and completed. We return
// STATUS_MORE_PROCESSING_REQUIRED here to let the I/O manager know we aren't
// done with the system power IRP.
//
return STATUS_MORE_PROCESSING_REQUIRED;
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrHandleDevicePowerIrp
//
// Entry point to handle DEVICE power IRPs
//
// INPUTS:
//
// DeviceObject - Pointer to our device object.
// Irp - Address of the device power IRP.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// STATUS_PENDING if we are going to handle the IRP,
// otherwise the NTSTATUS value of the driver below us
//
// IRQL:
//
// This routine is called at IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// This routine is called in an arbitrary thread context
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS OsrHandleDevicePowerIrp(PDEVICE_OBJECT DeviceObject,PIRP Irp) {
PUSBFX2LK_EXT devExt = (PUSBFX2LK_EXT)DeviceObject->DeviceExtension;
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
POWER_STATE powerState;
NTSTATUS status;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("OsrHandleDevicePowerIrp: Entered...\n"));
//
// Which power state are we talking about?
//
powerState = ioStack->Parameters.Power.State;
//
// For ALL power IRPs, we are REQUIRED to:
//
// 1) call PoStartNextPowerIrp()
// 2) Pass the IRP down to the next lower driver, unless
// we complete the request with an error.
//
switch(ioStack->MinorFunction) {
case IRP_MN_QUERY_POWER:
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_POWER_INFO,
("OsrHandleDevicePowerIrp: Querying Device state transition to %s\n",
OsrPrintDevicePowerState(powerState.DeviceState)));
//
// We will always accept the device QUERY_POWER
// for our device.
//
// A device may need to start queuing inbound I/O requests
// here. If a device does queue new requests on power down
// then it must have some method of restarting those requests
// when the device is returned to full power. When and where
// to start queuing requests is device specific and could
// possibly be postponed until the SET_POWER IRP arrives.
// However, it is typically when a QUERY_POWER IRP for the
// device is received that a driver starts queuing requests.
//
//
// Enter the POWER_PROCESSING state, all I/O
// requests will be queued
//
OsrUpdateDeviceState(devExt, STATE_POWER_PROCESSING);
//
// Setup our completion routine that just calls PoStartNextPowerIrp.
//
// See DevicePowerIoCompletionRoutine for an explanation
// of why we wait until the Irp comes back up to
// call PoStartNextPowerIrp...
//
IoMarkIrpPending(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
DevicePowerIoCompletionRoutine,
(PVOID)devExt,
TRUE,
TRUE,
TRUE);
//
// Pass the device power irp down using PoCallDriver!
// It is an error to use IoCallDriver here...Power irps
// must be passed down with PoCallDriver, since it
// will do some additional work to ensure proper
// synchronization of power Irps
//
(VOID)PoCallDriver(devExt->DeviceToSendIrpsTo,
Irp);
//
// We've registered an IO completion routine so we're not
// finished with this Irp...DON'T release our remove lock!
//
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("OsrHandleDevicePowerIrp: Exiting!\n"));
//
// We've marked the Irp pending so we MUST
// return STATUS_PENDING
//
return STATUS_PENDING;
case IRP_MN_SET_POWER:
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_POWER_INFO,
("OsrHandleDevicePowerIrp: Setting Device state to %s\n",
OsrPrintDevicePowerState(powerState.DeviceState)));
//
// We need to determine if we are powering up, powering down, or if
// the device's power state is not changing.
//
if(devExt->DevicePowerState > powerState.DeviceState) {
//
// This is a power up, we send the IRP down so the PDO can power up
// first, then we finish our processing in an I/O completion routine.
//
IoMarkIrpPending(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
DevicePowerIoCompletionRoutine,
(PVOID)devExt,
TRUE,
TRUE,
TRUE);
//
// Pass the irp down using PoCallDriver! It is an
// error to use IoCallDriver here...Power irps
// must be passed down with PoCallDriver, since it
// will do some additional work to ensure proper
// synchronization of power Irps
//
(VOID)PoCallDriver(devExt->DeviceToSendIrpsTo,
Irp);
//
// We've registered an IO completion routine so we're not
// finished with this Irp...DON'T release our remove lock!
//
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("OsrHandleDevicePowerIrp: Exiting!\n"));
//
// The IRP is marked pending so we
// MUST return STATUS_PENDING here.
//
return STATUS_PENDING;
} else if (devExt->DevicePowerState < powerState.DeviceState) {
//
// Power down case. We handle it first and send the IRP to the bus
// with a completion routine that calls PoStartNextPowerIrp
//
// See DevicePowerIoCompletionRoutine for an explanation
// of why we wait until the Irp comes back up to
// call PoStartNextPowerIrp...
//
//
//
// Notify the power manager of our device power state change
//
PoSetPowerState(DeviceObject,
DevicePowerState,
powerState);
IoMarkIrpPending(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(
Irp,
DevicePowerIoCompletionRoutine,
(PVOID)devExt,
TRUE,
TRUE,
TRUE);
//
// Pass the irp down using PoCallDriver! It is an
// error to use IoCallDriver here...Power irps
// must be passed down with PoCallDriver, since it
// will do some additional work to ensure proper
// synchronization of power Irps
//
(VOID)PoCallDriver(devExt->DeviceToSendIrpsTo,
Irp);
//
// We've registered an IO completion routine so we're not
// finished with this Irp...DON'T release our remove lock!
//
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("OsrHandleDevicePowerIrp: Exiting!\n"));
//
// The IRP is marked pending so we
// MUST return STATUS_PENDING here.
//
return STATUS_PENDING;
} else {
//
// Else we're staying at the same power state.
// There's no reason to touch our hardware, so
// we're just going to set our completion routine
// and call PoStartNextPowerIrp in the completion routine.
//
// See DevicePowerIoCompletionRoutine for an explanation
// of why we wait until the Irp comes back up to
// call PoStartNextPowerIrp...
//
IoMarkIrpPending(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(
Irp,
DevicePowerIoCompletionRoutine,
(PVOID)devExt,
TRUE,
TRUE,
TRUE);
//
// Pass the irp down using PoCallDriver! It is an
// error to use IoCallDriver here...Power irps
// must be passed down with PoCallDriver, since it
// will do some additional work to ensure proper
// synchronization of power Irps
//
(VOID)PoCallDriver(devExt->DeviceToSendIrpsTo,
Irp);
//
// We've registered an IO completion routine so we're not
// finished with this Irp...DON'T release our remove lock!
//
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("OsrHandleDevicePowerIrp: Exiting!\n"));
//
// The IRP is marked pending so we
// MUST return STATUS_PENDING here.
//
return STATUS_PENDING;
}
//
// We never get here...
//
return STATUS_UNSUCCESSFUL;
case IRP_MN_WAIT_WAKE:
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_POWER_INFO,
("OsrHandleDevicePowerIrp: IRP_MN_WAIT_WAKE received.\n"));
IoMarkIrpPending(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(
Irp,
(PIO_COMPLETION_ROUTINE)WaitWakeCompletionRoutine,
devExt,
TRUE,
TRUE,
TRUE);
PoStartNextPowerIrp(Irp);
status = PoCallDriver(devExt->DeviceToSendIrpsTo, Irp);
if(!NT_SUCCESS(status)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_POWER_INFO,
("OsrHandleDevicePowerIrp: Lower drivers failed the wait-wake Irp\n"));
}
status = STATUS_PENDING;
//
// push back the count HERE and NOT in completion routine
// a pending Wait Wake Irp should not impede stopping the device
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("OsrHandleDevicePowerIrp: Exit..\n"));
return STATUS_PENDING;
case IRP_MN_BOGUS:
//
// Driver Verifier bogus minor function code
//
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO,
("OsrHandleDevicePowerIrp: Received IRP_MN_BOGUS: Just pass it along...\n"));
//
// Fall through...
//
case IRP_MN_POWER_SEQUENCE:
//
// This device does not support wake or power sequence so
// we just send the request down to the bus
//
//
// Fall through...
//
default:
//
// Unknown power code...
//
//
// No matter what we always must call
// PoStartNextPowerIrp...
//
// We must also always make this call BEFORE calling
// IoSkipCurrentIrpStackLocation. Why? Because
// PoStartNextPowerIrp lets another power Irp of
// the same kind that we're processing now through
// (System or Device). How does it know what kind
// of Irp we're handling? Why from the current
// stack location of course!
//
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
//
// Pass the irp down using PoCallDriver! It is an
// error to use IoCallDriver here...Power irps
// must be passed down with PoCallDriver, since it
// will do some additional work to ensure proper
// synchronization of power Irps
//
status = PoCallDriver(devExt->DeviceToSendIrpsTo, Irp);
//
// We're done with this request
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("OsrHandleDevicePowerIrp: Exiting!\n"));
return status;
}
//
// We never get here...
//
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_POWER_INFO,
("OsrHandleDevicePowerIrp: Should never reach the end! Breaking into the debugger if attached...\n"));
//
// Use KdBreakPoint instead of DbgBreakPoint so that
// we only break in the checked build...
//
KdBreakPoint();
return STATUS_UNSUCCESSFUL;
}
///////////////////////////////////////////////////////////////////////////////
//
// DevicePowerIoCompletionRoutine
//
// Our I/O completion routine for device power up IRPs.
//
// INPUTS:
//
// DeviceObject - Pointer to device object.
// Irp - Address of the DEVICE power IRP.
// Context - the device extension
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// NTSTATUS value signalling the I/O manager to continue processing IRP
// stack locations or not.
//
// IRQL:
//
// This routine is called at IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// This routine is called in an arbitrary thread context
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS DevicePowerIoCompletionRoutine(PDEVICE_OBJECT DeviceObject,PIRP Irp,
PVOID Context)
{
PUSBFX2LK_EXT devExt = (PUSBFX2LK_EXT) Context;
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
POWER_STATE powerState;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("DevicePowerIoCompletionRoutine: Entered...\n"));
switch (ioStack->MinorFunction) {
case IRP_MN_SET_POWER: {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_POWER_INFO, ("DevicePowerIoCompletionRoutine: IRP_MN_SET_POWER\n"));
//
// for SET_POWER we actually need to do some work...
//
//
// If the IRP failed for any reason, there is
// no reason to change any state.
//
if(!NT_SUCCESS(Irp->IoStatus.Status)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_POWER_INFO,
("DevicePowerIoCompletionRoutine: Device Power Irp failed with status 0x%8.8x (%s)!\n",
Irp->IoStatus.Status, OsrNtStatusToString(Irp->IoStatus.Status)));
break;
}
powerState.DeviceState = ioStack->Parameters.Power.State.DeviceState;
//
// Powering up the device or staying at the same
// power state...
//
if(devExt->DevicePowerState >= powerState.DeviceState) {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_POWER_INFO,
("DevicePowerIoCompletionRoutine: IRP_MN_SET_POWER Device powered up or stayed the same.\n"));
//
// Notify the power manager of the device power state change.
//
PoSetPowerState(DeviceObject,
DevicePowerState,
powerState);
devExt->DevicePowerState = powerState.DeviceState;
//
// Restore our state to STATE_STARTED
//
OsrUpdateDeviceState(devExt, STATE_STARTED);
//
// If we powered up and Wait Wake is Enabled, then Issue a
// Wait wake Request.
//
if(devExt->DevicePowerState == PowerDeviceD0 &&
devExt->WaitWakeEnable) {
IssueWaitWake(devExt);
}
//
// If we have gone to full power, and we are in an applicable state
// we need to restart the queues.
// OsrProcessQueuedRequests checks the power state for us before
// starting any queues.
//
OsrProcessQueuedRequests(devExt);
} else {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_POWER_INFO,
("DevicePowerIoCompletionRoutine: IRP_MN_SET_POWER Device powered down\n"));
}
//
// Update the power state in our device extension
//
devExt->DevicePowerState = powerState.DeviceState;
break;
}
default: {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_POWER_INFO, ("DevicePowerIoCompletionRoutine: %08.8x %s\n",
ioStack->MinorFunction,OsrMinorFunctionToString(ioStack->MajorFunction,ioStack->MinorFunction)));
break;
}
}
//
// Let the power manager know we are ready to handle
// the next DevicePowerState power IRP. Why did we
// wait until the Irp came back up before calling this
// routine? Well, it's actually pretty subtle.
// PoStartNextPowerIrp makes sure that we are only
// handling at most one D Irp and one S Irp at any
// time. We're handling a D Irp here so if we called
// PoStartNextPowerIrp on the way DOWN the stack, a
// request to power up could be coming UP the stack
// and a request to power down would be allowed to come
// DOWN the stack (or vice versa). We'd break the implied
// synchronization of only having one D Irp in the
// stack at any time, which could cause race conditions...
//
// Note that the failure case is different. If we need to
// fail an Irp in our OsrPower handler we can legally call
// PoStartNextPowerIrp and then complete the Irp with an
// error.
//
// Also note that if we receive a Power Irp with a minor
// function that we don't support we can also call
// PoStartNextPowerIrp in OsrPower and just pass the Irp
// down without a completion routine.
//
// Is it confusing enough yet?
//
PoStartNextPowerIrp(Irp);
//
// We're done with this request
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("DevicePowerIoCompletionRoutine: Exiting!\n"));
return STATUS_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
//
// DevicePowerRequestCompletionRoutine
//
// Power request completion routine for device QUERY_POWER and SET_POWER IRPs.
//
// INPUTS:
//
// DeviceObject - Pointer to device object.
// MinorFunction - Power IRP's minor function code
// PowerState - The attempted device power state.
// Context - the device extension
// IoStatus - status block indicating the success or failure of the
// power IRP.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None.
//
// IRQL:
//
// This routine is called at IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// This routine is called in an arbitrary thread context
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
VOID DevicePowerRequestCompletionRoutine(PDEVICE_OBJECT DeviceObject,UCHAR MinorFunction,
POWER_STATE PowerState,PVOID Context,PIO_STATUS_BLOCK IoStatus)
{
PUSBFX2LK_EXT devExt = (PUSBFX2LK_EXT) Context;
PIRP systemPowerIrp;
UNREFERENCED_PARAMETER(DeviceObject);
UNREFERENCED_PARAMETER(MinorFunction);
UNREFERENCED_PARAMETER(PowerState);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("DevicePowerRequestCompletionRoutine: Entered...\n"));
//
// Get the system power IRP from our context
//
systemPowerIrp = devExt->SystemPowerIrp;
//
// This should not happen
//
ASSERT(NULL != systemPowerIrp);
//
// NULL out our temp storage for the IRP
//
devExt->SystemPowerIrp = NULL;
//
// Let the power manager know we are ready to handle
// the next SystemPowerState power IRP.
//
PoStartNextPowerIrp(systemPowerIrp);
//
// We complete the system power IRP here with the returned device
// power IRP's status. If any driver failed the device power IRP,
// the error is propagated to the system IRP this way.
//
systemPowerIrp->IoStatus.Status = IoStatus->Status;
//
// And we're done!
//
IoCompleteRequest(systemPowerIrp, IO_NO_INCREMENT);
//
// We're done with this request. We acquired the
// lock in OsrPower, so we'll use OsrPower as the
// tag here also
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_POWER_INFO, ("DevicePowerRequestCompletionRoutine: Exiting!\n"));
}
///////////////////////////////////////////////////////////////////////////////
//
// IssueWaitWake
//
// This routine issues a WAIT_WAKE request in order enable the USB device
// to awaken in response to a user hitting the wake up button on the device.
//
// INPUTS:
//
// DevExt - Pointer to our Device Extension.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None.
//
// IRQL:
//
// This routine is called at IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// This routine is called in an arbitrary thread context
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS IssueWaitWake(PUSBFX2LK_EXT DevExt)
{
NTSTATUS status;
POWER_STATE wakeState;
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
VALID_DEVEXT(DevExt);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WAIT_WAKE, ("IssueWaitWake: Entered\n"));
//
// Make sure that there is not a currently outstanding WaitWake request.
//
if(InterlockedExchange(&DevExt->FlagWWOutstanding, 1)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_WAIT_WAKE,
("IssueWaitWake: Wait Wake already outstanding, exit processing.\n"));
return STATUS_DEVICE_BUSY;
}
InterlockedExchange(&DevExt->FlagWWCancel, 0);
//
// Set up the System State from which the USB device is capable of waking
// up the system. Note that this information comes from the Device Capabilites
// information. This information must be filled in before we do the IssueWaitWake
// call.
//
wakeState.SystemState = DevExt->DeviceCapabilities.SystemWake;
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_WAIT_WAKE,
("IssueWaitWake: Issue Wait Wake for System state transition to %s\n",
OsrPrintSystemPowerState(wakeState.SystemState)));
//
// Request a Power Irp to deliver the Wait Wake Request.
status = PoRequestPowerIrp(DevExt->PhysicalDeviceObject,
IRP_MN_WAIT_WAKE,
wakeState,
(PREQUEST_POWER_COMPLETE) WaitWakeCallback,
DevExt,
&DevExt->WaitWakeIrp);
if(!NT_SUCCESS(status)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_WAIT_WAKE,
("IssueWaitWake: Device Power Irp failed with status 0x%8.8x (%s)!\n",
status, OsrNtStatusToString(status)));
InterlockedExchange(&DevExt->FlagWWOutstanding, 0);
}
//
// Retun the Status to the Caller.
//
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WAIT_WAKE, ("IssueWaitWake: Exit\n"));
return status;
}
///////////////////////////////////////////////////////////////////////////////
//
// CancelWaitWake
//
// This routine cancels an outstanding WAIT_WAKE request.
//
// INPUTS:
//
// DevExt - Pointer to our Device Extension.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None.
//
// IRQL:
//
// This routine is called at IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// This routine is called in an arbitrary thread context
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
VOID CancelWaitWake(PUSBFX2LK_EXT DevExt)
{
PIRP Irp;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WAIT_WAKE,("CancelWaitWake: Entered.\n"));
//
// Attempt to grab the WaitWake irp out of the Device Extension.
//
Irp = (PIRP) InterlockedExchangePointer((volatile PVOID*) &DevExt->WaitWakeIrp, NULL);
//
// See if we got the Irp, if we did, then we can try to cancel it.
//
if(Irp) {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_WAIT_WAKE,
("CancelWaitWake: Canceling Wait Wake Irp.\n"));
//
// Got the Irp, Cancel It.
//
IoCancelIrp(Irp);
//
// Indicate that the Irp was canceled so that the
// WaitWakeCompletion routine knows what is going on.
//
if(InterlockedExchange(&DevExt->FlagWWCancel, 1)) {
//
// Tell the Power Manager that we are ready to
// handle another Power Irp.
//
PoStartNextPowerIrp(Irp);
//
// Complete the Wait Wake Irp with a Canceled
// status.
//
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
}
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WAIT_WAKE,("CancelWaitWake: Exit.\n"));
}
///////////////////////////////////////////////////////////////////////////////
//
// WaitWakeCompletionRoutine
//
// This routine is a completion routine that gets called when the WaitWake
// Irp is completed.
//
// INPUTS:
//
// DeviceObject - Pointer to our Device Object.
// Irp - Completing Irp
// DevExt - Address of our Device Extension
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None.
//
// IRQL:
//
// This routine is called at IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// This routine is called in an arbitrary thread context
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS WaitWakeCompletionRoutine(PDEVICE_OBJECT DeviceObject,PIRP Irp,PUSBFX2LK_EXT DevExt)
{
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
VALID_DEVEXT(DevExt);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WAIT_WAKE,("WaitWakeCompletionRoutine: Entered.\n"));
//
// Propagate the Pending Returned Flag if Set.
//
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((volatile PVOID*)&DevExt->WaitWakeIrp, NULL)) {
//
// The CancelWaitWake routine already got the Irp.
//
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_WAIT_WAKE,
("WaitWakeCompletionRoutine: Wait Wake Irp Completed by CancelWaitWake.\n"));
//
// Tell the Power Manager we are ready for another Power Irp.
//
PoStartNextPowerIrp(Irp);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WAIT_WAKE,("WaitWakeCompletionRoutine: Exit.\n"));
return STATUS_SUCCESS;
}
//
// CancelWaitWake has run.
// If FlagWWCancel != 0, complete the Irp.
// If FlagWWCancel == 0, CancelWaitWake completes it.
//
if(InterlockedExchange(&DevExt->FlagWWCancel, 1)) {
//
// CancelWaitWake has not run, so we must complete the Irp.
//
//
// Tell the Power Manager we are ready for another Power Irp.
//
PoStartNextPowerIrp(Irp);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WAIT_WAKE,
("WaitWakeCompletionRoutine: Exit Irp Not Canceled.\n"));
return STATUS_CANCELLED;
}
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WAIT_WAKE,("WaitWakeCompletionRoutine: Exit.\n"));
//
// Tell the I/O Manager that we want to hold on to the IRP.
//
return STATUS_MORE_PROCESSING_REQUIRED;
}
///////////////////////////////////////////////////////////////////////////////
//
// WaitWakeCallback
//
// This routine is a completion routine that is called when the IRP_MN_WAIT_WAKE
// Power request has completed.
//
// INPUTS:
//
// DeviceObject - Pointer to our Device Object.
// MinorFunction - Minor Function of the Power Irp Completing
// PowerState - Current Device Power State
// Context - Address of our Device Extension
// IoStatus - Completion Status.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None.
//
// IRQL:
//
// This routine is called at IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// This routine is called in an arbitrary thread context
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
VOID WaitWakeCallback(PDEVICE_OBJECT DeviceObject,UCHAR MinorFunction,POWER_STATE PowerState,
PVOID Context,PIO_STATUS_BLOCK IoStatus)
{
PUSBFX2LK_EXT devExt = (PUSBFX2LK_EXT) Context;
ASSERT(MinorFunction == IRP_MN_WAIT_WAKE);
VALID_DEVEXT(devExt);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WAIT_WAKE,
("WaitWakeCallback: Entered status = 0x%x (%s)\n",IoStatus->Status,
OsrNtStatusToString(IoStatus->Status)));
//
// Indicate that there is no Wait Wake Irp Outstanding.
//
InterlockedExchange(&devExt->FlagWWOutstanding, 0);
//
// Make sure that the Irp Completed Successfully
//
if(!NT_SUCCESS(IoStatus->Status)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_WAIT_WAKE,
("WaitWakeIrpCompletionFunc: Error 0x%x (%s).\n",
IoStatus->Status,OsrNtStatusToString(IoStatus->Status)));
return;
}
//
// We may need to be the one to power the device up now (because we were
// armed for wake but the system was in S0). We'll do this power
// up asynchronously
//
SSPowerUpDeviceAsync(devExt);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WAIT_WAKE,("WaitWakeCallback: Exit.\n"));
return;
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrPrintSystemPowerState
//
// This routine translates the input system power state to a string
//
// INPUTS:
//
// State - System Power State.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None.
//
// IRQL:
//
// This routine is called at IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// This routine is called in an arbitrary thread context
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
PCHAR OsrPrintSystemPowerState(SYSTEM_POWER_STATE State) {
PCHAR string;
switch(State) {
case PowerSystemUnspecified: // = 0,
string = (PCHAR) "PowerSystemUnspecified";
break;
case PowerSystemWorking: //,
string = (PCHAR) "PowerSystemWorking";
break;
case PowerSystemSleeping1: //,
string = (PCHAR) "PowerSystemSleeping1";
break;
case PowerSystemSleeping2: //,
string = (PCHAR) "PowerSystemSleeping2";
break;
case PowerSystemSleeping3: //,
string = (PCHAR) "PowerSystemSleeping3";
break;
case PowerSystemHibernate: //,
string = (PCHAR) "PowerSystemHibernate";
break;
case PowerSystemShutdown: //,
string = (PCHAR) "PowerSystemShutdown";
break;
case PowerSystemMaximum: //
string = (PCHAR) "PowerSystemMaximum";
break;
default:
string = (PCHAR) "Unknown Power State ?????? Error";
break;
}
return string;
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrPrintPowerAction
//
// This routine translates the input power action to a string
//
// INPUTS:
//
// Action - Power Action.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None.
//
// IRQL:
//
// This routine is called at IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// This routine is called in an arbitrary thread context
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
PCHAR OsrPrintPowerAction(POWER_ACTION Action)
{
PCHAR string;
switch(Action) {
case PowerActionNone: // = 0,
string = (PCHAR) "PowerActionNone";
break;
case PowerActionReserved: //,
string = (PCHAR) "PowerActionReserved";
break;
case PowerActionSleep: //,
string = (PCHAR) "PowerActionSleep";
break;
case PowerActionHibernate: //,
string = (PCHAR) "PowerActionHibernate";
break;
case PowerActionShutdown: //,
string = (PCHAR) "PowerActionShutdown";
break;
case PowerActionShutdownReset: //,
string = (PCHAR) "PowerActionShutdownReset";
break;
case PowerActionShutdownOff: //,
string = (PCHAR) "PowerActionShutdownOff";
break;
case PowerActionWarmEject: //
string = (PCHAR) "PowerActionWarmEject";
break;
default:
string = (PCHAR) "Unknown Power Action ???? Error";
break;
}
return string;
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrPrintDevicePowerState
//
// This routine translates the input device power state to a string
//
// INPUTS:
//
// State - Device Power State.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None.
//
// IRQL:
//
// This routine is called at IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// This routine is called in an arbitrary thread context
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
PCHAR OsrPrintDevicePowerState(DEVICE_POWER_STATE State)
{
PCHAR string;
switch(State) {
case PowerDeviceUnspecified: // = 0,
string = (PCHAR) "PowerDeviceUnspecified";
break;
case PowerDeviceD0: //,
string = (PCHAR) "PowerDeviceD0";
break;
case PowerDeviceD1: //,
string = (PCHAR) "PowerDeviceD1";
break;
case PowerDeviceD2: //,
string = (PCHAR) "PowerDeviceD2";
break;
case PowerDeviceD3: //,
string = (PCHAR) "PowerDeviceD3";
break;
case PowerDeviceMaximum: //
string = (PCHAR) "PowerDeviceMaximum";
break;
default:
string = (PCHAR) "Unknown Device Power State ???? Error";
break;
}
return string;
}
///////////////////////////////////////////////////////////////////////////////
//
// OsrPrintPowerStateType
//
// This routine translates the input Power state type to a string
//
// INPUTS:
//
// Type - Power State Type.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None.
//
// IRQL:
//
// This routine is called at IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// This routine is called in an arbitrary thread context
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
PCHAR OsrPrintPowerStateType(POWER_STATE_TYPE Type)
{
PCHAR string;
switch(Type) {
case SystemPowerState:// = 0,
string = (PCHAR) "SystemPowerState";
break;
case DevicePowerState: //
string = (PCHAR) "DevicePowerState";
break;
default:
string = (PCHAR) "Unknown POWER_STATE_TYPE";
break;
}
return string;
}
///////////////////////////////////////////////////////////////////////////////
//
// PrintDeviceCapabilities
//
// This routine outputs a DEVICE_CAPABILITES structure
//
// INPUTS:
//
// PParentCapabilities - Address of capabilities to display.
// Title - Display Title String
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None.
//
// IRQL:
//
// This routine is called at IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// This routine is called in an arbitrary thread context
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
VOID PrintDeviceCapabilities(PDEVICE_CAPABILITIES PParentCapabilities,PUCHAR Title)
{
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\n%s Device Capabilities %p\n",
(CCHAR*) Title,PParentCapabilities));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tSize = %x\n",PParentCapabilities->Size));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tVersion = %x\n",PParentCapabilities->Version)); // the version documented here is version 1
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tDeviceD1 %s\n",PParentCapabilities->DeviceD1 ? "TRUE" : "FALSE"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tDeviceD2 %s\n",PParentCapabilities->DeviceD2 ? "TRUE" : "FALSE"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tLockSupported %s\n",PParentCapabilities->LockSupported ? "TRUE" : "FALSE"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tEjectSupported %s\n",PParentCapabilities->EjectSupported ? "TRUE" : "FALSE")); // Ejectable in S0
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tRemovable %s\n",PParentCapabilities->Removable ? "TRUE" : "FALSE"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tDockDevice %s\n",PParentCapabilities->DockDevice ? "TRUE" : "FALSE"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tUniqueID %s\n",PParentCapabilities->UniqueID ? "TRUE" : "FALSE"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tSilentInstall %s\n",PParentCapabilities->SilentInstall ? "TRUE" : "FALSE"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tRawDeviceOK %s\n",PParentCapabilities->RawDeviceOK ? "TRUE" : "FALSE"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tSurpriseRemovalOK %s\n",PParentCapabilities->SurpriseRemovalOK ? "TRUE" : "FALSE"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tWakeFromD0 %s\n",PParentCapabilities->WakeFromD0 ? "TRUE" : "FALSE"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tWakeFromD1 %s\n",PParentCapabilities->WakeFromD1 ? "TRUE" : "FALSE"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tWakeFromD2 %s\n",PParentCapabilities->WakeFromD2 ? "TRUE" : "FALSE"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tWakeFromD3 %s\n",PParentCapabilities->WakeFromD3 ? "TRUE" : "FALSE"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tHardwareDisabled %s\n",PParentCapabilities->HardwareDisabled ? "TRUE" : "FALSE"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tNonDynamic %s\n",PParentCapabilities->NonDynamic ? "TRUE" : "FALSE"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tWarmEjectSupported %s\n",PParentCapabilities->WarmEjectSupported ? "TRUE" : "FALSE"));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tNoDisplayInUI %s\n",PParentCapabilities->NoDisplayInUI ? "TRUE" : "FALSE"));
// ULONG Reserved:14;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tAddress %x\n",PParentCapabilities->Address));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tUINumber %x\n",PParentCapabilities->UINumber));
for(ULONG i = 0; i < PowerSystemMaximum; i++) {
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\t%s = %s\n",OsrPrintSystemPowerState((SYSTEM_POWER_STATE)i),
OsrPrintDevicePowerState(PParentCapabilities->DeviceState[i])));
}
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tSystemWake = %s\n",OsrPrintSystemPowerState(PParentCapabilities->SystemWake)));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tDeviceWake = %s\n",OsrPrintDevicePowerState(PParentCapabilities->DeviceWake)));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tD1Latency %x\n",PParentCapabilities->D1Latency));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tD2Latency %x\n",PParentCapabilities->D2Latency));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\tD3Latency %x\n",PParentCapabilities->D3Latency));
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_PNP_INFO,("\n"));
}