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

📄 pmdevice.cpp

📁 此代码为WCE5.0下电源管理的源代码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
    // return no change if the new state is unchanged or is invalid
    // (for example, if DevicePowerNotify() while processing 
    // IOCTL_POWER_CAPABILITIES)
    if(curDx == newDx || ! VALID_DX(newDx)) {
        newDx = PwrDeviceUnspecified;
    }

    return newDx;
}

// This routine examines a device's current power state information with
// regards to system power state and floor and ceiling restrictions.  It
// returns TRUE if successful and FALSE otherwise.  If successful, new 
// values for the device's current, floor, and ceiling power states are
// passed back via pointers.  If the caller is not interested in the
// new values for floor and ceiling power levels, it may pass in null
// for these parameters.  The caller should hold the PM lock.
BOOL
GetNewDeviceStateInfo(PCEDEVICE_POWER_STATE pNewFloorDx, 
                      PCEDEVICE_POWER_STATE pNewCeilingDx,
                      PDEVICE_STATE pds, PSYSTEM_POWER_STATE psps, 
                      PDEVICE_POWER_RESTRICTION pFloorDxList,
                      PDEVICE_POWER_RESTRICTION pCeilingDxList)
{
    BOOL fOk = TRUE;
    LPCGUID pGuid = pds->pListHead->pGuid;
    DEVICEID devId;
    PDEVICE_POWER_RESTRICTION pdpr;
    CEDEVICE_POWER_STATE newFloorDx, newCeilingDx;
    SETFNAME(_T("GetNewDeviceStateInfo"));

    PREFAST_DEBUGCHK(psps != NULL);
    PREFAST_DEBUGCHK(pNewFloorDx != NULL);
    PREFAST_DEBUGCHK(pNewCeilingDx != NULL);

    // Assume the default ceiling state.  Since power ceilings are defined in
    // the registry, there should be at most one that matches the device's 
    // class and one that matches the device exactly.
    newCeilingDx = psps->defaultCeilingDx;

    // look for power restrictions that match this device's class
    devId.pGuid = pds->pListHead->pGuid;
    devId.pszName = NULL;
    if((pdpr = PowerRestrictionFindList(pCeilingDxList, &devId, NULL)) != NULL) {
        newCeilingDx = pdpr->devDx;
    }

    // look for power restrictions that match this device exactly
    devId.pszName = pds->pszName;
    if((pdpr = PowerRestrictionFindList(pCeilingDxList, &devId, NULL)) != NULL) {
        newCeilingDx = pdpr->devDx;
    }

    // Assume the default floor (device turned off).  There may be multiple
    // power floors specified in the registry so we will have to look for
    // matches of several different types.
    newFloorDx = D4;

    // are we ignoring application requirements in this system power state?
    if((psps->dwFlags & (POWER_STATE_CRITICAL | POWER_STATE_OFF)) == 0) {
        BOOL fNeedForce;

        // is the default for this power state to ignore application requirements?
        if((psps->dwFlags & POWER_STATE_SUSPEND) != 0) {
            fNeedForce = TRUE;
        } else {
            fNeedForce = FALSE;
        }

        // no, look for the least restricted floor based on device class for any
        // system power state
        devId.pszName = NULL;
        pdpr = pFloorDxList;
        while((pdpr = PowerRestrictionFindList(pdpr, &devId, NULL)) != NULL) {
            if(pdpr->devDx < newFloorDx
            && (fNeedForce == FALSE || (pdpr->dwFlags & POWER_FORCE) != 0)) {
                newFloorDx = pdpr->devDx;
            }
            pdpr = pdpr->pNext;
        }
        
        // look for the least restricted floor based on device class for
        // this system power state
        devId.pszName = NULL;
        pdpr = pFloorDxList;
        while((pdpr = PowerRestrictionFindList(pdpr, &devId, psps->pszName)) 
            != NULL) {
            if(pdpr->devDx < newFloorDx
            && (fNeedForce == FALSE || (pdpr->dwFlags & POWER_FORCE) != 0)) {
                newFloorDx = pdpr->devDx;
            }
            pdpr = pdpr->pNext;
        }
        
        // look for the least restricted floor based on an exact 
        // match with this device for any system power state
        devId.pszName = pds->pszName;
        pdpr = pFloorDxList;
        while((pdpr = PowerRestrictionFindList(pdpr, &devId, NULL)) != NULL) {
            if(pdpr->devDx < newFloorDx
            && (fNeedForce == FALSE || (pdpr->dwFlags & POWER_FORCE) != 0)) {
                newFloorDx = pdpr->devDx;
            }
            pdpr = pdpr->pNext;
        }
        
        // look for the least restricted floor based on an exact 
        // match with this device for this system power state
        devId.pszName = pds->pszName;
        pdpr = pFloorDxList;
        while((pdpr = PowerRestrictionFindList(pdpr, &devId, psps->pszName)) 
            != NULL) {
            if(pdpr->devDx < newFloorDx
            && (fNeedForce == FALSE || (pdpr->dwFlags & POWER_FORCE) != 0)) {
                newFloorDx = pdpr->devDx;
            }
            pdpr = pdpr->pNext;
        }
    }

    // pass back values
    if(fOk) {
        *pNewCeilingDx = newCeilingDx;
        *pNewFloorDx = newFloorDx;
    }

    return fOk;
}
// This routine updates a device's power state variables.  This routine
// should be called whenever a device is added to the system or whenever
// a device power restriction is created, modified, or destroyed.
BOOL
UpdateDeviceState(PDEVICE_STATE pds)
{
    BOOL fOk = TRUE;
    DWORD dwStatus = ERROR_SUCCESS;
    DWORD dwRetryCount = 0 ;
    SETFNAME(_T("UpdateDeviceState"));

    do {
        CEDEVICE_POWER_STATE newDx = PwrDeviceUnspecified;
        CEDEVICE_POWER_STATE oldLastReqDx;
        BOOL fForce = FALSE;
        
        PMLOCK();
        // get the new device power state (based on the last device power state
        // the device wanted -- this value is initialized to D0 in case the 
        // device never makes any power requests on its own.
        fOk = GetNewDeviceStateInfo(&pds->floorDx, &pds->ceilingDx,
            pds, gpSystemPowerState, gpFloorDx, gpCeilingDx);
        if(fOk) {
            // We have to monitor changes to pds->lastReqDx, since multiple threads can be 
            // in the PM at once calling DevicePowerNotify().
            newDx = GetNewDeviceDx(pds->lastReqDx, pds->curDx, pds->setDx, pds->floorDx, pds->ceilingDx);
            if(newDx == PwrDeviceUnspecified && (pds->dwNumPending != 0 || dwStatus == ERROR_RETRY)) {
                PMLOGMSG(ZONE_DEVICE, 
                    (_T("%s: reentrant set for '%s', setting %d\r\n"), pszFname, pds->pszName, pds->curDx));
                newDx = pds->curDx;
                fForce = TRUE;
            }
            PMLOGMSG(ZONE_DEVICE, 
                (_T("%s: new state for '%s' is %d (current %d, req %d, set %d, floor %d, ceiling %d, actual %d)\r\n"),
                pszFname, pds->pszName, newDx, pds->curDx, pds->lastReqDx, pds->setDx, pds->floorDx, pds->ceilingDx, pds->actualDx));
            oldLastReqDx = pds->lastReqDx;
            dwStatus = ERROR_SUCCESS;
        }
        PMUNLOCK();

        // do we need to update the device?
        if(fOk && newDx != PwrDeviceUnspecified) {
            // yes, set its power state to the new value
            dwStatus = SetDevicePower(pds, newDx, fForce);
            if(dwStatus == ERROR_SUCCESS) {
                PMLOCK();
                PMLOGMSG(ZONE_DEVICE, 
                    (_T("%s: updated state for '%s' is current %d, req %d, set %d, floor %d, ceiling %d, actual %d\r\n"),
                    pszFname, pds->pszName, pds->curDx, pds->lastReqDx, pds->setDx, pds->floorDx, pds->ceilingDx, pds->actualDx));
                if(pds->lastReqDx != oldLastReqDx) {
                    PMLOGMSG(ZONE_DEVICE, (_T("%s: race detected on '%s', setting ERROR_RETRY\r\n"),
                        pszFname, pds->pszName));
                    dwStatus = ERROR_RETRY;
                }
                PMUNLOCK();
            }
            
            if(dwStatus == ERROR_RETRY) {
                dwRetryCount++;
                PMLOGMSG(ZONE_DEVICE, (_T("%s: retrying(%d) SetDevicePower('%s', D%d)\r\n"), 
                    pszFname,dwRetryCount, pds->pszName, newDx));
            } else if(dwStatus != ERROR_SUCCESS) {
                PMLOGMSG(ZONE_DEVICE, (_T("%s: SetDevicePower('%s', D%d) failed %d\r\n"), 
                    pszFname, pds->pszName, newDx, dwStatus));
                fOk = FALSE;
            }
        }
    } while(fOk && dwStatus == ERROR_RETRY);

    return fOk;
}

#ifdef PM_SUPPORTS_DEVICE_QUERIES

// NOTE -- Devices are not required to implement IOCTL_POWER_QUERY, nor is the 
// PM required to pay attention to the value that devices return in response to the
// query.  If the POWER_FORCE flag is set, the PM is not required to make the request.
// This means that device drivers cannot count on IOCTL_POWER_QUERY being invoked
// at all, so by default, the PM does not use IOCTL_POWER_QUERY at all.  
//
// However, some OEMs may choose to query drivers on every system power state
// transition and to always honor the device's response.  Such OEMs may 
// find the code inside this #ifdef useful.  This code may not be present
// in future source updates to the Power Manager.

// This routine queries a driver as to whether it is ready to handle a device
// power state transition.  It returns TRUE or FALSE according to the response;
// FALSE may also indicate an error talking to the device.
BOOL
QueryDevicePowerUpdate(PDEVICE_STATE pds, CEDEVICE_POWER_STATE newDx)
{
    BOOL fOk = TRUE;
    POWER_RELATIONSHIP pr;
    PPOWER_RELATIONSHIP ppr = NULL;
    CEDEVICE_POWER_STATE reqDx;
    BOOL fDoSet;
    BOOL fOpenDevice = FALSE;
    HANDLE hDevice = INVALID_HANDLE_VALUE;
    SETFNAME(_T("QueryDevicePower"));
    
    DEBUGCHK(pds != NULL && 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)\r\n"), 
        pszFname, pds->pszName, newDx, reqDx));

    // make a last check to see if we really need to send the device an update
    PMLOCK();
    if(reqDx != pds->actualDx) {
        fDoSet = TRUE;
        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);
        }

        // do we have one?
        if(hDevice == INVALID_HANDLE_VALUE) {
            PMLOGMSG(ZONE_WARN, (_T("%s: couldn't open '%s'\r\n"), pszFname,
                pds->pszName));
            fOk = FALSE;
        } else {
            CEDEVICE_POWER_STATE tmpDx = newDx;
            DWORD dwBytesReturned;
            DEBUGCHK(pds->pInterface->pfnRequestDevice != NULL);
            fOk = pds->pInterface->RequestDevice(hDevice, IOCTL_POWER_QUERY, ppr, 
                ppr == NULL ? 0 : sizeof(*ppr), &tmpDx, sizeof(tmpDx), 
                &dwBytesReturned);
            if(!fOk) {
                PMLOGMSG(ZONE_WARN, 
                    (_T("%s: '%s' failed IOCTL_POWER_QUERY D%d, status is %d\r\n"),
                    pszFname, pds->pszName, newDx, GetLastError()));
            }
            
            // close the device handle if we opened it in this routine
            if(fOpenDevice) {
                DEBUGCHK(pds->pInterface->pfnCloseDevice != NULL);
                pds->pInterface->pfnCloseDevice(hDevice);
            }
            
            // if the device permitted the ioctl, determine its response to the 
            // query.
            if(fOk) {
                if(tmpDx == PwrDeviceUnspecified) {
                    PMLOGMSG(ZONE_WARN, (_T("%s: '%s' rejected IOCTL_POWER_QUERY D%d\r\n"),
                        pszFname, pds->pszName, newDx));
                    fOk = FALSE;
                }
            }
        }
    }

    return fOk;
}

// This routine determines what power state a device would enter in a new
// system power state and asks the device whether it is ready to enter
// that state.  It returns TRUE or FALSE depending on the device's response;
// false may also indicate an error.    
BOOL

⌨️ 快捷键说明

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