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")); 
}