⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbfx2lk_selsusp.cpp

📁 基于vc++6.0环境的cypress USB 驱动源代码
💻 CPP
📖 第 1 页 / 共 4 页
字号:

            }

        }

    } else {

        //
        // If SS is not initialized, we should NEVER
        //  be called here and not at D0. If so, then
        //  the caller either didn't check the PnP state
        //  before calling here or the PnP state machine
        //  is broken.
        //
        ASSERT(DevExt->DevicePowerState == PowerDeviceD0);

    }

    KeReleaseSpinLock(&DevExt->SSLock,oldIrql);

#ifndef W2K

    //
    // If we got an idle IRP, we're going to need to 
    //  cancel it
    //
    if (idleIrp) {

        //
        // Cancel the IRP
        //
        IoCancelIrp(idleIrp);

        //
        // Wait for the IRP to finish
        //
        (VOID)OsrWaitForSingleObject(&DevExt->SSIdleCompletionRoutineCalled);

        //
        // We got the IRP, so we free it. 
        //
        IoFreeIrp(idleIrp);

    }

#endif

    if (queuePowerUp) {

        //
        // We need to power the device ourselves
        //
        SSPowerUpDeviceAsync(DevExt);

    }

    //
    // If we queued the power up IRP or there
    //  was already a power up queued, indicate
    //  that the device is suspended by returning
    //  TRUE
    //
    return (queuePowerUp || powerUpQueued);

}


///////////////////////////////////////////////////////////////////////////////
//
// SSSubmissionThreadRoutine
//
//      This thread runs while the device is attached to the system. Its goal
//      in life is to wake up when the device no longer has any active I/O
//      and attempt to suspend it
//
//  INPUTS:
//
//      Context  -  One of our device extensions
//
//  OUTPUTS:
//
//      None
//
//  RETURNS:
//
//      None
//
//  IRQL:
//
//      IRQL == PASSIVE_LEVEL
//
//  CONTEXT:
//
//      System context
//
//  NOTES:
//
///////////////////////////////////////////////////////////////////////////////
VOID SSSubmissionThreadRoutine(PVOID Context) 
{
    PUSBFX2LK_EXT devExt = (PUSBFX2LK_EXT)Context;
    NTSTATUS status;
    PVOID waitObjects[2];
    LARGE_INTEGER delay;
    LARGE_INTEGER currentTime;
    LARGE_INTEGER timeSinceIdle;
    KIRQL oldIrql;
    BOOLEAN powerDeviceBackUp;
    BOOLEAN restartQueues;

    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_SELECTIVE_SUSPEND,
                            ("SSSubmissionThreadRoutine: Entered.\n"));

    //
    // Define an arbitrary thread delay that we'll add to
    //  our loop. 
    //
    delay.QuadPart = RELATIVE(SECONDS(1));

    

    //
    // Wait on the STOP event, which is signaled when the oustanding
    //  I/O count on the device drops to 1 and also the  
    //  thread termination event, 
    //
    waitObjects[0] = &devExt->StopEvent;
    waitObjects[1] = &devExt->SSSubmissionThreadTerminateEvent;

    //
    // Loop forever...
    //
    while (TRUE) {

        //
        // Wait on our above two events. 
        //  
        // We don't use OsrWaitForMultipleObjects here
        //  because we expect to be just sit here for a 
        //  loooong time and the otherwise helpful debug output 
        //  produced by OsrWaitForMultipleObjects just becomes 
        //  noise in this case
        //
        status = KeWaitForMultipleObjects(2,
                                          waitObjects,
                                          WaitAny,
                                          Executive,
                                          KernelMode,
                                          FALSE,
                                          NULL,
                                          NULL);

        //
        // We expect a wait status indicating that either 
        //  the stop event was fired OR that the 
        //  terminate thread event was fired. Anything else is an
        //  error.
        //
        if (status != STATUS_WAIT_0) {

            OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_SELECTIVE_SUSPEND,
               ("EnableSelectiveSuspend: KeWaitForMultipleObjects returned "\
                                                    "0x%x (%s). Exiting...\n",
                status,OsrNtStatusToString(status)));

            PsTerminateSystemThread(status);
            return;

        }

        //
        // Default to not needing to power the device up
        //  or restarting the queues, let the logic below 
        //  change this as necessary.
        //
        powerDeviceBackUp = FALSE;
        restartQueues = FALSE;

        //
        // Grab the current time. We'll use this to determine if
        //  the device has been idle long enough.
        //
        KeQuerySystemTime(&currentTime);


        //
        // We need to try to suspend the device
        //
        KeAcquireSpinLock(&devExt->SSLock,&oldIrql);

        //
        // If the device can suspend right now AND 
        //  we haven't been suspended, we'll do the power
        //  down.
        //
        // Not that while the device is suspended, the stop
        //  event stays fired so we'll keep coming back here
        //  every "delay" seconds and check it. This isn't an
        //  optimal solution, as it requires polling even if 
        //  the device is already idle or SS is disabled by the
        //  user, but it does provide for a fairly straightforward
        //  SS implementation. SS is very difficult to get correct,
        //  so we have chosen to not attempt to optimize and provide
        //  something that is safe instead. Whether or not this is 
        //  acceptable to your application is a design decision
        //  that you will have to make.
        //
        if (devExt->SSDeviceCanNowSuspend && 
            devExt->SSState == SS_NOT_STARTED) { 


            //
            // Calculate how long it has been since the 
            //  device became idle
            //
            timeSinceIdle.QuadPart = 
                  currentTime.QuadPart - 
                            devExt->SSTimeOfLastActivity.QuadPart;


            //
            // Is the difference sufficient to constitute an idle
            //  device?
            //
            if (timeSinceIdle.QuadPart >= SS_DEVICE_IDLE_DELAY) {
            
                //
                // We're about to power down the device, set the state
                //  to SS_PROCESSING
                //
                devExt->SSState = SS_PROCESSING;

                //
                // Clear the "device is out of selective suspend" event
                //
                KeClearEvent(&devExt->SSDeviceNotSuspendedEvent);

                //
                // We don't need this again until the device
                //  has suspended. The fact that we have 
                //  set the state to SS_PROCESSING will
                //  cause any arriving operations that need the
                //  device fully powered to queue (we'll deal
                //  with getting them started again once we've processed 
                //  the power down).
                //
                // Note that we're being overly cautious and a bit
                //  obtuse with our selective suspend algorithm here.
                //  If an operation comes in at this point we don't 
                //  try to cancel the in progress power down. Instead,
                //  we wait for the device to power all the way down 
                //  and then we'll power it back up again before restarting
                //  the queues. This is a safe approach (as it eliminates
                //  many race conditions) but it may not be ideal for 
                //  your environment.
                //
                KeReleaseSpinLock(&devExt->SSLock,oldIrql);

                //
                // Synchronously suspend the device.
                //
#ifndef W2K
                //
                // If we're not built for Windows 2000 compatibility,
                //  we can't just power the device down, we need to let
                //  the USB hus driver know about it first. In this case
                //  we'll call SSSuspendDeviceWithCallback which will
                //  send the appropriate IRP and power down from within
                //  the callback
                // 
                SSSuspendDeviceWithCallback(devExt);
#else
                //
                // Otherwise, there is no concept of notifiying the bus
                //  driver first. So, just power the device down inline
                //
                SSSuspendDevice(devExt);
#endif

                //
                // Acquire our lock again and see if the state of the 
                //  world has changed. If not, then we'll set our
                //  SS state to be SUSPENDED. If it HAS changed, then
                //  we need to power up the device again
                //
                KeAcquireSpinLock(&devExt->SSLock,&oldIrql);

                //
                // Make sure that the power down actually succeeded. 
                //  If not, then there's nothing to be done
                //
                if (devExt->DevicePowerState != devExt->PowerDownLevel) {
                    
                    OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_SELECTIVE_SUSPEND,
                        ("SSSubmissionThreadRoutine: Power down of device did"\
                                  " not succeed. Device power state is 0x%x\n",
                        devExt->DevicePowerState));

                    devExt->SSState = SS_NOT_STARTED;

                    //
                    // Set the "device is now out of selective suspend" event
                    //
                    KeSetEvent(&devExt->SSDeviceNotSuspendedEvent, 
                               EVENT_INCREMENT,
                               FALSE);

                    //
                    // Restart the queues that were stalled 
                    //  as part of the powering down
                    //
                    restartQueues = TRUE;

                } else {

                    //
                    // Is everyone still OK with us suspending the device?
                    //
                    if (devExt->SSDeviceCanNowSuspend == TRUE) {

                        //
                        // Yup, no one wants the device just yet sp
                        //  the Device is now suspended!
                        //
                        devExt->SSState = SS_SUSPENDED;

                    } else {

                        //
                        // Whoops. While we were powering down, a request
                        //  came in that required access to the device.
                        //  Power back up again once we've dropped the lock
                        //
                        powerDeviceBackUp = TRUE;

                    }

                }

                //
                // Lock acquisition above isn't leaked, it's released by
                //  the upcoming KeRelease outside of the original IF
                //

            }

        }

        KeReleaseSpinLock(&devExt->SSLock,oldIrql);

        if (powerDeviceBackUp) {

            //
            // While we were powering the device down, 
            //  a request came in that needed the device
            //  to be powered. Power the device back up
            //  here. 
            //
            
            //
            // We never leave the "selective suspend
            //  processing" state in this case, which 
            //  allows us to queue all of those operations
            //  that requested the power up.
            //
            // The power up code deals with getting the 
            //  queues restarted by calling OsrProcessQueuedRequests
            //
            ASSERT(devExt->SSState == SS_PROCESSING);

            SSPowerUpDevice(devExt);

        }

        if (restartQueues) {

            //
            // The suspend failed for whatever reason and the
            //  queues need to be restarted
            //
            OsrProcessQueuedRequests(devExt);

        }


        //
        // Put a bit of a delay in. Because the stop
        //  event is a notification event, we'll keep
        //  hitting this loop while suspended so 
        //  the delay just leaves some breathing room.
        //
        KeDelayExecutionThread(KernelMode,
                               FALSE,
                               &delay);

    }

    return;

}


///////////////////////////////////////////////////////////////////////////////
//
// SSPowerUpDevice
//
//      This routine synchronously powers up the device
//
//  INPUTS:
//
//      DevExt  -  One of our device extensions
//
//  OUTPUTS:
//
//      None
//
//  RETURNS:
//
//      None
//
//  IRQL:
//
//      IRQL == PASSIVE_LEVEL
//
//  CONTEXT:
//
//      Arbitrary
//
//  NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
VOID SSPowerUpDevice(PUSBFX2LK_EXT DevExt) 
{

    POWER_STATE devicePowerState;
    KEVENT powerUpCompleteEvent;
    NTSTATUS status;

    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_SELECTIVE_SUSPEND,
                                ("SSPowerUpDevice: Entered\n"));

    //
    // We should not already be in D0 at this point
    //
    ASSERT(DevExt->DevicePowerState != PowerDeviceD0);

    //
    // Submit a device power IRP to our device
    //

    //
    // This constitutes a new I/O on the device, 
    //  so bump the oustanding I/O count
    //
    OsrIncrementOutstandingIoCount(DevExt,__FILE__,__LINE__);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -