📄 pmdevice.cpp
字号:
QueryDeviceStateUpdate(PDEVICE_STATE pds, PSYSTEM_POWER_STATE psps,
PDEVICE_POWER_RESTRICTION pFloorDx,
PDEVICE_POWER_RESTRICTION pCeilingDx)
{
BOOL fOk = TRUE;
CEDEVICE_POWER_STATE floorDx, ceilingDx;
CEDEVICE_POWER_STATE newDx = PwrDeviceUnspecified;
SETFNAME(_T("QueryDeviceState"));
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(&floorDx, &ceilingDx, pds, psps, pFloorDx, pCeilingDx);
if(fOk) {
newDx = GetNewDeviceDx(pds->lastReqDx, pds->curDx, pds->setDx, floorDx, ceilingDx);
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));
}
PMUNLOCK();
// do we need to update the device?
if(fOk && newDx != PwrDeviceUnspecified) {
// yes, see if the device is able to update its power state to the new value
fOk = QueryDevicePowerUpdate(pds, newDx);
}
return fOk;
}
// This routine asks all registered devices if they are ready to make device
// power state transitions to a new system power state. It returns TRUE if all
// responses are positive, FALSE otherwise.
BOOL
QueryClassDevices(PDEVICE_LIST pdl, PSYSTEM_POWER_STATE psps, PDEVICE_POWER_RESTRICTION pdprCeiling,
PDEVICE_POWER_RESTRICTION pdprFloor)
{
BOOL fOk = TRUE;
BOOL fDeviceRemoved;
PDEVICE_STATE pds;
SETFNAME(_T("QueryClassDevices"));
DEBUGCHK(pdl != NULL);
PMLOCK();
// Since it's possible that the device list may be modified
// while we are not holding the PM critical section we need
// to watch out for the device we are working on getting removed.
// We increment the reference count to keep the device data
// structure from being deallocated out from under us. Once
// the device update is complete and we have the critical section
// again, we check to see if it's still part of the device list.
// If it's not, we start again at the top of the list.
do {
fDeviceRemoved = FALSE;
pds = pdl->pList;
while(fOk && !fDeviceRemoved && pds != NULL) {
PDEVICE_STATE pdsNext;
DeviceStateAddRef(pds); // keep the device pointer alive
PMUNLOCK();
fOk = QueryDeviceStateUpdate(pds, psps, pdprFloor, pdprCeiling);
PMLOCK();
// is the device still on the list?
if(pds->pListHead == NULL) {
// device disappeared while we were accessing it
PMLOGMSG(ZONE_WARN || ZONE_DEVICE,
(_T("%s: device '%s' removed during update\r\n"), pszFname,
pds->pszName));
fDeviceRemoved = TRUE;
} else {
// save the next pointer so we don't try to
// dereference pds after decrementing its use count.
pdsNext = pds->pNext;
}
DeviceStateDecRef(pds); // done with the device pointer
if(!fDeviceRemoved) pds = pdsNext; // on to the next
}
} while(fOk && (fDeviceRemoved || pds != NULL));
PMUNLOCK();
PMLOGMSG(!fOk && ZONE_WARN, (_T("%s: returning %d\r\n"), pszFname, fOk));
return fOk;
}
// This routine asks all registered devices if they are ready to make device
// power state transitions to a new system power state. It returns TRUE if all
// responses are positive, FALSE otherwise.
BOOL
QueryAllDevices(PSYSTEM_POWER_STATE psps, PDEVICE_POWER_RESTRICTION pdprCeiling,
PDEVICE_POWER_RESTRICTION pdprFloor)
{
PDEVICE_LIST pdl;
BOOL fOk = TRUE;
SETFNAME(_T("QueryAllDevices"));
// update all devices of all classes
for(pdl = gpDeviceLists; fOk && pdl != NULL; pdl = pdl->pNext) {
fOk = QueryClassDevices(pdl, psps, pdprCeiling, pdprFloor);
}
PMLOGMSG(!fOk && ZONE_WARN, (_T("%s: returning %d\r\n"), pszFname, fOk));
return fOk;
}
#endif // PM_SUPPORTS_DEVICE_QUERIES
// This routine updates state for all devices. It should be called during
// system power state transitions so that device power states can be
// adjusted appropriately.
VOID
UpdateClassDeviceStates(PDEVICE_LIST pdl)
{
BOOL fDeviceRemoved;
PDEVICE_STATE pds;
SETFNAME(_T("UpdateClassDeviceStates"));
PREFAST_DEBUGCHK(pdl != NULL);
PMLOCK();
// Since it's possible that the device list may be modified
// while we are not holding the PM critical section we need
// to watch out for the device we are working on getting removed.
// We increment the reference count to keep the device data
// structure from being deallocated out from under us. Once
// the device update is complete and we have the critical section
// again, we check to see if it's still part of the device list.
// If it's not, we start again at the top of the list. This should
// be harmless since devices that are at the right power state
// already won't be updated.
do {
fDeviceRemoved = FALSE;
pds = pdl->pList;
while(!fDeviceRemoved && pds != NULL) {
PDEVICE_STATE pdsNext;
DeviceStateAddRef(pds); // keep the device pointer alive
PMUNLOCK();
UpdateDeviceState(pds);
PMLOCK();
// is the device still on the list?
if(pds->pListHead == NULL) {
// device disappeared while we were accessing it
PMLOGMSG(ZONE_WARN || ZONE_DEVICE,
(_T("%s: device '%s' removed during update\r\n"), pszFname,
pds->pszName));
fDeviceRemoved = TRUE;
} else {
// save the next pointer so we don't try to
// dereference pds after decrementing its use count.
pdsNext = pds->pNext;
}
DeviceStateDecRef(pds); // done with the device pointer
if(!fDeviceRemoved) pds = pdsNext; // on to the next
}
} while(fDeviceRemoved || pds != NULL);
PMUNLOCK();
}
// This routine updates state for all devices of all classes. It can be called during
// system power state transitions so that device power states can be
// adjusted appropriately.
VOID
UpdateAllDeviceStates(VOID)
{
PDEVICE_LIST pdl;
// update all devices of all classes
for(pdl = gpDeviceLists; pdl != NULL; pdl = pdl->pNext) {
UpdateClassDeviceStates(pdl);
}
}
// this routine checks to see if a device pointer is actually on a
// list someplace. If it finds it, it increments its reference
// count and returns true.
BOOL
CheckDevicePointer(PDEVICE_STATE pds)
{
PDEVICE_LIST pdl;
BOOL fFound = FALSE;
// look for a match
DEBUGCHK(pds != NULL);
PMLOCK();
for(pdl = gpDeviceLists; pdl != NULL && !fFound; pdl = pdl->pNext) {
PDEVICE_STATE pdsTraveller;
for(pdsTraveller = pdl->pList; pdsTraveller != NULL;
pdsTraveller = pdsTraveller->pNext) {
if(pdsTraveller == pds) {
fFound = TRUE;
break;
}
}
}
// did we find the device?
if(fFound) {
// yes, update its reference count
DeviceStateAddRef(pds);
}
PMUNLOCK();
return fFound;
}
// This routine adds a device to the list associated with its device class.
// This routine does not return a value; it will either create a new
// device state structure and add it to a list or it will not. If the new
// device duplicates an existing one this routine won't create a new node.
// This routine executes in the context of the PnP thread, which handles
// device interface additions and removals.
VOID
AddDevice(LPCGUID guidDevClass, LPCTSTR pszName, PDEVICE_STATE pdsParent,
PPOWER_CAPABILITIES pCaps)
{
SETFNAME(_T("AddDevice"));
PMLOGMSG(ZONE_DEVICE,
(_T("%s: adding '%s', pdsParent 0x%08x, pCaps 0x%08x to class %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\r\n"),
pszFname, pszName, pdsParent, pCaps,
guidDevClass->Data1, guidDevClass->Data2, guidDevClass->Data3,
(guidDevClass->Data4[0] << 8) + guidDevClass->Data4[1], guidDevClass->Data4[2], guidDevClass->Data4[3],
guidDevClass->Data4[4], guidDevClass->Data4[5], guidDevClass->Data4[6], guidDevClass->Data4[7]));
// figure out onto which list this device should be added
PDEVICE_LIST pdl = GetDeviceListFromClass(guidDevClass);
// did we find the list?
if(pdl != NULL) {
// check for duplicates
PDEVICE_STATE pds = DeviceStateFindList(pdl, pszName);
// create the device if it doesn't already exist
if(pds == NULL) {
BOOL fOk = FALSE;
pds = DeviceStateCreate(pszName);
if(pds != NULL) {
// if we are passed the device's capabilities, just copy them
// into the structure
if(pCaps != NULL) {
__try {
pds->caps = *pCaps;
}
__except(EXCEPTION_EXECUTE_HANDLER) {
PMLOGMSG(ZONE_WARN,
(_T("%s: exception during capabilities copy from 0x%08x\r\n"),
pszFname, pCaps));
pCaps = NULL;
}
}
// update the device's parent pointer
if(pdsParent != NULL) {
DeviceStateAddRef(pdsParent);
}
pds->pParent = pdsParent;
// add the new device to its class list
if(!DeviceStateAddList(pdl, pds)) {
// deallocate the node, reference count isn't incremented
DeviceStateDecRef(pds);
pds = NULL;
} else {
PREFAST_DEBUGCHK(pds->pInterface != NULL);
PREFAST_DEBUGCHK(pds->pInterface->pfnOpenDevice != NULL);
PREFAST_DEBUGCHK(pds->pInterface->pfnRequestDevice != NULL);
PREFAST_DEBUGCHK(pds->pInterface->pfnCloseDevice != NULL);
pds->hDevice = pds->pInterface->pfnOpenDevice(pds);
if(pds->hDevice == INVALID_HANDLE_VALUE) {
PMLOGMSG(ZONE_WARN, (_T("%s: couldn't open device '%s'\r\n"),
pszFname, pszName != NULL ? _T("<NULL>") : pszName));
} else {
// do we need to request capabilities?
fOk = TRUE; // assume success
if(pCaps == NULL) {
DWORD dwBytesReturned;
POWER_RELATIONSHIP pr;
PPOWER_RELATIONSHIP ppr = NULL;
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 = ≺
}
// get the device's capabilities structure
fOk = pds->pInterface->pfnRequestDevice(pds->hDevice, IOCTL_POWER_CAPABILITIES,
ppr, ppr == NULL ? 0 : sizeof(*ppr),
&pds->caps, sizeof(pds->caps), &dwBytesReturned);
// sanity check the size in case a device is just returning
// a good status on all ioctls for some reason
if(fOk && dwBytesReturned != sizeof(pds->caps)) {
PMLOGMSG(ZONE_WARN,
(_T("%s: invalid size returned from IOCTL_POWER_CAPABILITIES\r\n"),
pszFname));
fOk = FALSE;
}
}
// any problems so far?
if(fOk) {
// determine whether we should request power relationships from a parent device
if((pds->caps.Flags & POWER_CAP_PARENT) != 0) {
pds->pInterface->pfnRequestDevice(pds->hDevice, IOCTL_REGISTER_POWER_RELATIONSHIP,
NULL, 0, NULL, 0, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -