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

📄 pmdevice.cpp

📁 此代码为WCE5.0下电源管理的源代码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//

//
// This module contains routines for keeping track of devices and 
// managing device power.
//

#include <pmimpl.h>

// This routine determines how to map a device power state that the
// PM wants to use into the device power states that a particular
// device actually supports.
CEDEVICE_POWER_STATE
MapDevicePowerState(CEDEVICE_POWER_STATE newDx, UCHAR ucSupportedDx)
{
    CEDEVICE_POWER_STATE reqDx;
    SETFNAME(_T("MapDevicePowerState"));

    DEBUGCHK(newDx >= D0 && newDx <= D4);

    // map the power level to whatever the device actually supports.  All devices
    // are required to support D0 so we won't even check for it.
    reqDx = newDx;
    if(reqDx == D3 && (ucSupportedDx & (1 << reqDx)) == 0) reqDx = D4;
    if(reqDx == D4) {
        if((ucSupportedDx & (1 << reqDx)) == 0) reqDx = D3;
        if((ucSupportedDx & (1 << reqDx)) == 0) reqDx = D2;
    }
    if(reqDx == D2 && (ucSupportedDx & (1 << reqDx)) == 0) reqDx = D1;
    if(reqDx == D1 && (ucSupportedDx & (1 << reqDx)) == 0) reqDx = D0;

    PMLOGMSG(ZONE_DEVICE, (_T("%s: mapping D%d to D%d\r\n"), pszFname, newDx, reqDx));
    return reqDx;
}
    

// This routine actually tells a device to update its current power state.  It 
// returns TRUE if successful, FALSE otherwise.  Note that devices don't always
// update their power state to the level that the PM wants.  Some devices may
// not support all power states, for example.  Devices are responsible for mapping
// PM requests to device power levels that they actually support.
DWORD
SetDevicePower(PDEVICE_STATE pds, CEDEVICE_POWER_STATE newDx, BOOL fForceSet = FALSE)
{
    DWORD dwStatus = ERROR_SUCCESS;
    static DWORD dwStaticRefCount = 0; 
    DWORD dwCurRefCount = 0;
    CEDEVICE_POWER_STATE reqDx;
    CEDEVICE_POWER_STATE oldActualDx, oldCurDx;
    POWER_RELATIONSHIP pr;
    PPOWER_RELATIONSHIP ppr = NULL;
    BOOL fDoSet;
    BOOL fOpenDevice = FALSE;
    HANDLE hDevice = INVALID_HANDLE_VALUE;
    SETFNAME(_T("SetDevicePower"));

    PREFAST_DEBUGCHK(pds != NULL);
    DEBUGCHK( newDx >= D0 && newDx <= D4);
    DEBUGCHK(pds->pInterface != NULL);

    // map the power level to whatever the device actually supports
    reqDx = MapDevicePowerState(newDx, pds->caps.DeviceDx);
    PMLOGMSG(ZONE_DEVICE, (_T("%s: setting '%s' to D%d (mapped to D%d), fForceSet is %d\r\n"), 
        pszFname, pds->pszName, newDx, reqDx, fForceSet));

    // make a last check to see if we really need to send the device an update
    PMLOCK();
    DEBUGCHK(pds->dwNumPending == 0 || pds->pendingDx != PwrDeviceUnspecified);
    DEBUGCHK(pds->dwNumPending != 0 || pds->pendingDx == PwrDeviceUnspecified);
    if(reqDx != pds->actualDx || pds->dwNumPending != 0 || fForceSet) {
        fDoSet = TRUE;

        // record what we're trying to set, visible to other threads
        pds->pendingDx = reqDx;
        pds->dwNumPending++;
        // Re-Enter Checking Count.
        dwStaticRefCount ++ ;
        dwCurRefCount = dwStaticRefCount;
        // remember what we're trying to set in this thread
        oldCurDx = pds->curDx;
        oldActualDx = pds->actualDx;

        // get a handle to the device to make the request
        hDevice = pds->hDevice;
        if(hDevice != INVALID_HANDLE_VALUE) {
            fOpenDevice = FALSE;    // already have a handle
        } else {
            fOpenDevice = TRUE;     // need to open a handle
        }
    } else {
        fDoSet = FALSE;
    }
    PMUNLOCK();

    // are we doing an update?
    if(!fDoSet) {
        PMLOGMSG(ZONE_DEVICE, (_T("%s: device is already at D%d\r\n"), pszFname, reqDx));
    } else {
        // initialize parameters
        memset(&pr, 0, sizeof(pr));
        if(pds->pParent != NULL) {
            PMLOGMSG(ZONE_DEVICE, (_T("%s: parent of '%s' is '%s'\r\n"), 
                pszFname, pds->pszName, pds->pParent->pszName));
            pr.hParent = (HANDLE) pds->pParent;
            pr.pwsParent = pds->pParent->pszName;
            pr.hChild = (HANDLE) pds;
            pr.pwsChild = pds->pszName;
            ppr = &pr;
        }
        
        // get a handle to the device
        if(fOpenDevice) {
            DEBUGCHK(pds->pInterface->pfnOpenDevice != NULL);
            hDevice = pds->pInterface->pfnOpenDevice(pds);
        }

        // did we get a handle?
        if(hDevice == INVALID_HANDLE_VALUE) {
            PMLOGMSG(ZONE_WARN, (_T("%s: couldn't open '%s'\r\n"), pszFname,
                pds->pszName));
            dwStatus = ERROR_INVALID_HANDLE;
        } else {
            DWORD dwBytesReturned;
            DEBUGCHK(pds->pInterface->pfnRequestDevice != NULL);

            BOOL fOk = pds->pInterface->pfnRequestDevice(hDevice, IOCTL_POWER_SET, ppr, 
                ppr == NULL ? 0 : sizeof(*ppr), &reqDx, sizeof(reqDx), 
                &dwBytesReturned);

            if(fOk) {
                // Check for races to update the driver -- it is possible for the device to call
                // DevicePowerNotify() when another thread is calling SetDevicePower(), 
                // SetSystemPowerState(), or Set(/Release)PowerRequirement().
                PMLOCK();
                if(pds->pendingDx == reqDx) {
                    // record the new values
                    pds->curDx = newDx;
                    pds->actualDx = reqDx;
                } 
                else if (dwCurRefCount != dwStaticRefCount || pds->dwNumPending > 1 ) {
                    PMLOGMSG(ZONE_DEVICE, (_T("%s: race detected on '%s', returning ERROR_RETRY\r\n"),
                        pszFname, pds->pszName));
                    dwStatus = ERROR_RETRY;
                }
                else { // This condition indicate no SetDevicePower called by others. It must be wrong value return from device driver
                    RETAILMSG(1, (_T("%s: Wrong Return Value from '%s', returning ERROR_GEN_FAILURE\r\n"),
                        pszFname, pds->pszName));
                    ASSERT(FALSE);
                    dwStatus = ERROR_GEN_FAILURE;
                }
                dwStaticRefCount ++ ;
                PMUNLOCK();
            } else {
                dwStatus = GetLastError();
                if(dwStatus == ERROR_SUCCESS) {
                    dwStatus = ERROR_GEN_FAILURE;
                }
                PMLOGMSG(ZONE_WARN, (_T("%s: '%s' failed IOCTL_POWER_SET D%d, status is %d\r\n"),
                    pszFname, pds->pszName, newDx, dwStatus));
                
                PMLOCK();
                // the set operation failed -- if the device power state appears unchanged,
                // restore our state variables.  In general, devices should never fail a
                // set request.
                if(reqDx == oldActualDx) {
                    pds->curDx = oldCurDx;
                    pds->actualDx = oldActualDx;
                }
                PMUNLOCK();
            }
            
            // close the device handle if we opened it in this routine
            if(fOpenDevice) {
                DEBUGCHK(pds->pInterface->pfnCloseDevice != NULL);
                pds->pInterface->pfnCloseDevice(hDevice);
            }
        }

        // update reference counts
        PMLOCK();
        DEBUGCHK(pds->dwNumPending != 0);
        DEBUGCHK(pds->pendingDx != PwrDeviceUnspecified);
        pds->dwNumPending--;
        if(pds->dwNumPending == 0) {
            pds->pendingDx = PwrDeviceUnspecified;
        }
        PMUNLOCK();
    }

    return dwStatus;
}

// This routine sends an IOCTL_POWER_GET to a device to obtain its current
// device power state.  It returns ERROR_SUCCESS and fills in pCurDx if 
// successful.  Otherwise it returns an error code.
DWORD
GetDevicePower(PDEVICE_STATE pds, PCEDEVICE_POWER_STATE pCurDx)
{
    DWORD dwStatus = ERROR_GEN_FAILURE;
    POWER_RELATIONSHIP pr;
    PPOWER_RELATIONSHIP ppr = NULL;
    BOOL fOpenDevice;
    HANDLE hDevice;
    SETFNAME(_T("GetDevicePower"));

    PREFAST_DEBUGCHK(pds != NULL );
    PREFAST_DEBUGCHK(pCurDx != NULL);
    PREFAST_DEBUGCHK(pds->pInterface != NULL);

    // initialize parameters
    memset(&pr, 0, sizeof(pr));
    if(pds->pParent != NULL) {
        PMLOGMSG(ZONE_DEVICE, (_T("%s: parent of '%s' is '%s'\r\n"), 
            pszFname, pds->pszName, pds->pParent->pszName));
        pr.hParent = (HANDLE) pds->pParent;
        pr.pwsParent = pds->pParent->pszName;
        pr.hChild = (HANDLE) pds;
        pr.pwsChild = pds->pszName;
        ppr = &pr;
    }
    
    // get a handle to the device
    hDevice = pds->hDevice;
    if(hDevice != INVALID_HANDLE_VALUE) {
        fOpenDevice = FALSE;    // already have a handle
    } else {
        fOpenDevice = TRUE;     // need to open a handle
        DEBUGCHK(pds->pInterface->pfnOpenDevice != NULL);
        hDevice = pds->pInterface->pfnOpenDevice(pds);
    }

    // did we get a handle?
    if(hDevice == INVALID_HANDLE_VALUE) {
        PMLOGMSG(ZONE_WARN, (_T("%s: couldn't open '%s'\r\n"), pszFname,
            pds->pszName));
    } else {
        CEDEVICE_POWER_STATE tmpDx = PwrDeviceUnspecified;
        DWORD dwBytesReturned;
        DEBUGCHK(pds->pInterface->pfnRequestDevice != NULL);
        BOOL fOk = pds->pInterface->pfnRequestDevice(hDevice, IOCTL_POWER_GET, ppr, 
            ppr == NULL ? 0 : sizeof(*ppr), &tmpDx, sizeof(tmpDx), 
            &dwBytesReturned);
        
        // update variables and clear the requestor thread ID
        if(fOk) {
            if(VALID_DX(tmpDx)) {
                *pCurDx = tmpDx;
                dwStatus = ERROR_SUCCESS;
            } else {
                PMLOGMSG(ZONE_WARN, 
                    (_T("%s: '%s' IOCTL_POWER_GET returned invalid state %u\r\n"),
                    pszFname, pds->pszName, tmpDx));
                dwStatus = ERROR_INVALID_DATA;
            }
        } else {
            dwStatus = GetLastError();
        }
        
        PMLOGMSG(!fOk && ZONE_WARN, 
            (_T("%s: '%s' failed IOCTL_POWER_GET, status is %d\r\n"),
            pszFname, pds->pszName, GetLastError()));
        
        // close the device handle if we opened it in this routine
        if(fOpenDevice) {
            DEBUGCHK(pds->pInterface->pfnCloseDevice != NULL);
            pds->pInterface->pfnCloseDevice(hDevice);
        }
    }

    return dwStatus;
}

// This routine determines the mapping from a requested device power level
// to an actual new device power level.  This is based on whether or not
// a device power level has been set by the user and what the current 
// floor and ceiling device power levels are.  This routine returns the new
// device power level, or PwrDeviceUnspecified if the device is already
// at the desired power level.
CEDEVICE_POWER_STATE
GetNewDeviceDx(CEDEVICE_POWER_STATE reqDx, 
               CEDEVICE_POWER_STATE curDx, 
               CEDEVICE_POWER_STATE setDx, 
               CEDEVICE_POWER_STATE floorDx, 
               CEDEVICE_POWER_STATE ceilingDx)
{
    CEDEVICE_POWER_STATE newDx = reqDx;

    DEBUGCHK(reqDx != PwrDeviceUnspecified);
    DEBUGCHK(VALID_DX(reqDx));

    // determine which power state state to put the device into as a result
    // of this update.  The device may already be in a valid state, in which
    // case we don't need to do anything.
    if(setDx != PwrDeviceUnspecified) {
        newDx = setDx;
    } else {
        // no explicitly set power level, compare current values against
        // boundaries
        newDx = reqDx;                  // assume this setting is ok
        if(newDx < ceilingDx) {
            // lower power to the level of the ceiling
            newDx = ceilingDx;
        }
        if(floorDx < newDx) {
            // raise power to the level of the floor
            newDx = floorDx;
        }
    }

⌨️ 快捷键说明

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