IClass与电源管理
?
IClass與電源管理
?
前段時間為J9項目上添加電源管理,中間走了一些彎路。之前錯誤的認為,IClass只是與電源狀態的改變方法有關,也就是說IClass的正確與否只會影響到設備電源狀態的正確與否,而不會造成設備是否可以支持設備電源狀態的轉換。
結果后來整USB的時候,發現完全不是這么回事,郁悶了兩天。
擔心忘記了,電源管理中與IClass相關知識趕緊寫下來。
一.PM中的相關內容說明
1.結構體DEVICE_LIST
首先看一下結構體DEVICE_LIST的定義:
| // this structure describes a set of power manageable devices typedef struct _DeviceList_tag { ??? LPCGUID???? pGuid;????????????????? // class of device ??? PDEVICE_STATE pList;??????????????? // pointer to devices ??? HANDLE????? hMsgQ;????????????????? // device notification queue ??? HANDLE????? hnClass;??????????????? // handle from RequestDeviceNotifications() ??? PDEVICE_INTERFACE????? pInterface; // interface to the device class power management routines ??? struct _DeviceList_tag *pNext;????? // singly linked list pointer } DEVICE_LIST, *PDEVICE_LIST; |
可以看到其第一個成員pGuid指向了GUID的名字,大家都知道CE中的PM相關GUID有四個,分別是通用設備,網絡設備,塊設備和GWES設備。默認在注冊表[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Power/Interfaces]下進行聲明,它是通過PM.dll中的相關宏定義進行指定,可以將PM Driver移植到BSP下后進行修改。
典型的定義如下:
| ; Power Manager interfaces.? These list the interface classes that the Power ; Manager will monitor for new devices. ; [HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Power/Interfaces] ??? "{A32942B7-920C-486b-B0E6-92A702A99B35}"="Generic power-manageable devices" ??? "{8DD679CE-8AB4-43c8-A14A-EA4963FAA715}"="Power-manageable block devices" ; @CESYSGEN IF CE_MODULES_NDIS ??? "{98C5250D-C29A-4985-AE5F-AFE5367E5006}"="Power-manageable NDIS miniports" ; @CESYSGEN ENDIF CE_MODULES_NDIS ; @CESYSGEN IF CE_MODULES_GWES ??? "{EB91C7C9-8BF6-4a2d-9AB8-69724EED97D1}"="Power-manageable display" ; @CESYSGEN ENDIF CE_MODULES_GWES |
?
顯然,系統中應當維護著4個DEVICE_LIST結構體變量,它們最終組成一個單向鏈表,通過全局變量gpDeviceLists指向其表頭,該鏈表在函數DeviceListsInit()中進行初始化,而DeviceListsInit()由PmInit()進行調用。
2.結構體DEVICE_STATE
首先看一下結構體DEVICE_STATE的定義:
| // this structure describes a power-manageable device typedef struct _DeviceState_tag { ??? LPCTSTR???? pszName;??????????????? // device's name ??? CEDEVICE_POWER_STATE??? curDx;????? // current official power state (not necessarily supported by the device) ??? CEDEVICE_POWER_STATE??? floorDx;??? // minimum device power state, or PwrDeviceUnspecified ??? CEDEVICE_POWER_STATE??? ceilingDx;? // maximum device power state, or PwrDeviceUnspecified ??? CEDEVICE_POWER_STATE??? setDx; ?????// power state if explicitly set, or PwrDeviceUnspecified ??? CEDEVICE_POWER_STATE??? lastReqDx;? // last state requested by the device ??? CEDEVICE_POWER_STATE??? actualDx;?? // current actual device power state ??? CEDEVICE_POWER_STATE??? pendingDx;? // Pending DX for updating ??? DWORD?????????????????? dwNumPending; // Number of Pending for updating. ??? struct _DeviceState_tag *pParent;?? // parent device, or NULL ??? POWER_CAPABILITIES????? caps;?????? // as reported by the device ??? DWORD???? ??dwRefCount;???????????? // structure can be deallocated when this is 0 ??? HANDLE????? hDevice;??????????????? // handle to the device from OpenDevice(), or NULL ??? PDEVICE_INTERFACE?????? pInterface; // interface to the device class power management routines ??? struct _DeviceList_tag? *pListHead; // pointer to the containing list ??? struct _DeviceState_tag *pNext;???? // linked list pointers ??? struct _DeviceState_tag *pPrev; } DEVICE_STATE, *PDEVICE_STATE; |
?????? 可以看到,該鏈表是一個雙向鏈表,可以通過其前向和后驅雙向遍歷。
?????? 每一個由Device.exe(6.0下應該是kernel.exe)/GWES加載的設備以及網絡和通用設備都對應一個該結構體的變量。
每一類GUID設備會組成一個DEVICE_STATE鏈表,也就是說系統中最大只有四個這種鏈表,通過結構體DEVICE_LIST的pList成員進行指向。
?????? 好了,現在你可以知道要找到一個設備的DEVICE_STATE的方法了,就是先找到它對應的GUID類的DEVICE_LIST結構體,然后從該類結構體的pList里面遍歷特定的設備名找到你的DEVICE_STATE結點。
?????? 系統中已經實現了該函數,即GetDeviceListFromClass和DeviceStateFindList。GetDeviceListFromClass代碼如下:
| // this routine determines to which device list a particular device class // corresponds PDEVICE_LIST GetDeviceListFromClass(LPCGUID guidDevClass) { ??? PDEVICE_LIST pdl; ??? SETFNAME(_T("GetDeviceListFromClass")); ? ??? PREFAST_DEBUGCHK(guidDevClass != NULL); ? ??? // look for a match ??? __try { ??????? for(pdl = gpDeviceLists; pdl != NULL; pdl = pdl->pNext) { ??????????? if(*pdl->pGuid == *guidDevClass) { ??????????????? break; ???? ???????} ??????? } ??? } ??? __except(EXCEPTION_EXECUTE_HANDLER) { ??????? PMLOGMSG(TRUE, (_T("%s: exception accessing guidDevClass 0x%08x/r/n"), ??????????? pszFname, guidDevClass)); ??????? pdl = NULL; ??? } ? ??? return pdl; } |
?????? DeviceStateFindList代碼如下:
| // This routine looks for a device on a list.? If it finds the device, it // increments its reference counter and returns a pointer to it.? The caller // should decrement the reference counter when it is done with the pointer. // Note that the search is case sensitive. PDEVICE_STATE DeviceStateFindList(PDEVICE_LIST pdl, LPCTSTR pszName) { ??? PDEVICE_STATE pds; ??? SETFNAME(_T("DeviceStateFindList")); ? ??? PMLOCK(); ? ??? __try { ??????? // look for a match ??????? for(pds = pdl->pList; pds != NULL; pds = pds->pNext) { ??????????? if(_tcscmp(pds->pszName, pszName) == 0) { ??????????????? // increment the reference count and exit ??????????????? DeviceStateAddRef(pds); ??????????????? break; ??????????? } ??????? } ??? } ??? __except(EXCEPTION_EXECUTE_HANDLER) { ??????? PMLOGMSG(ZONE_WARN, (_T("%s: exception searching list/r/n"), pszFname)); ??????? pds = NULL; ??? } ? ??? PMUNLOCK(); ? ??? return pds; } |
3.指針函數結構體DEVICE_INTERFACE
?????? 首先看一下結構體DEVICE_INTERFACE的定義:
| typedef struct _DeviceInterface_tag { ??? BOOL (WINAPI * pfnInitInterface) (VOID); ??? HANDLE (WINAPI *pfnOpenDevice) (struct _DeviceState_tag *); ??? BOOL (WINAPI * pfnCloseDevice) (HANDLE); ??? BOOL (WINAPI * pfnRequestDevice) (HANDLE, DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD); } DEVICE_INTERFACE, *PDEVICE_INTERFACE; |
?????? 系統中共維護兩個該結構體的變量,即PM的MDD層Driver中定義的gStreamInterface和gDisplayInterface。
?????? 其中,gDisplayInterface對應的GWES加載的設備,而gStreamInterface對應的是網絡設備,塊驅動設備和通用設備。
?????? 其各個成員的意思就不再贅述。
二.IClass在電源管理中的用途
1.PM的相關初始化
1> 誰加載了PM.dll???
在CE5.0中,設備管理器是Device.exe,到6.0里面由于單個Process空間上了GB的級別,就將其改為Device.dll,掛在了Kernel.exe里面。慚愧的是對于6.0,小弟始終沒有找到在哪里LoadLibrary(“Device.dll”)。
小弟猜測應該是Filesys加載的PM.dll,幫助文檔中講述Filesys的啟動過程的時候也沒有提到這點,但是由于Filesys并沒有源碼,不知道各位有沒有比較好的方法可以驗證這一點。
2> PM的初始化
?????? Filesys.exe/Filesys.dll調用了Device.exe/Device.dll的導出函數StartDeviceManager(),而在函數StartDeviceManager()中調用了PM.dll導出的初始化函數PmInit()。
PmInit()首先調用DeviceListsInit()去查詢注冊表的配置并初始化DEVICE_LIST鏈表。函數DeviceListsInit()的代碼如下:
| // This routine reads the registry to determine what type of device interfaces // we will be monitoring.? The default PM GUID is ignored if present in the // registry and is always added last (so it's first in the list). BOOL DeviceListsInit(VOID) { ??? BOOL fOk = TRUE; ??? PDEVICE_LIST pdl; ??? DWORD dwStatus; ??? HKEY hk; ??? TCHAR szBuf[MAX_PATH]; ??? SETFNAME(_T("DeviceListsInit")); ? ??? // enumerate all the device classes ???? // 到注冊表[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Power/Interfaces]下 ???? // 獲取GUID的值,默認情況下,ICLASS共有類別,此處直接通過枚舉的方式查詢到每一個GUID ??? wsprintf(szBuf, _T("%s//Interfaces"), PWRMGR_REG_KEY); ??? dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szBuf, 0, 0, &hk); ??? if(dwStatus == ERROR_SUCCESS) { ??????? DWORD dwIndex = 0; ??????? do { ??????????? DWORD cbValueName = dim(szBuf), dwType; ??????????? GUID idInterface; ? ??????????? dwStatus = RegEnumValue(hk, dwIndex, szBuf, &cbValueName, NULL, ??????????????? &dwType, NULL, NULL); ??????????? if(dwStatus == ERROR_SUCCESS) { ??????????????? if(dwType != REG_SZ) { ??????????????????? PMLOGMSG(ZONE_WARN, (_T("%s: invalid type for value '%s'/r/n"), ??????????????????????? pszFname, szBuf)); ??????????????? } ?????????????????? // 將GUID進行轉換 ?????????????????? else if(!ConvertStringToGuid(szBuf, &idInterface)) { ??????????????????? PMLOGMSG(ZONE_WARN, (_T("%s: can't convert '%s' to GUID/r/n"), ??????????????????????? pszFname, szBuf)); ??????????????? } ?????????????????? // 如果是通用設備的GUID,則跳過,留到最后進行初始化其DEVICE_LIST ?????????????????? else if(idInterface == idGenericPMDeviceClass) { ??????????????????? PMLOGMSG(ZONE_INIT, (_T("%s: default GUID found in registry as expected/r/n"), ??????????????????????? pszFname)); ??????????????? } ?????????????????? // 為特定GUID類分配并初始化一個DEVICE_LIST結構體變量 ?????????????????? else if((pdl = DeviceListCreate(&idInterface)) == NULL) { ??????????????????? PMLOGMSG(ZONE_WARN, (_T("%s: DeviceListCreate() failed/r/n"), ??????????????????????? pszFname)); ??????????????? } ?????????????????? // 初始化上面分配的DEVICE_LIST結構體變量的成員pInterface,使其指向有效的函數指針結構體 ?????????????????? // 函數PlatformDeviceListInit這里非常重要,它初始化了DEVICE_LIST結構體變量的成員pInterface,而pInterface的具體實現包括gDisplayInterface和gStreamInterface,在pmstream.cpp和pmdisplay.cpp可以找到其具體的實現,代碼寫的蠻經典的 ?????????????????? // 這些函數指針結構體通過PM Driver的MDD層獲得 ?????????????????? else if(PlatformDeviceListInit(pdl) == FALSE) { ??????????????????? PMLOGMSG(ZONE_WARN, (_T("%s: PlatformDeviceListInit() failed/r/n"), ??????????????????????? pszFname)); ??????????????????? DeviceListDestroy(pdl); ??????????????? } ?????????????????? // 將當前GUID的DEVICE_LIST結構體變量添加鏈表gpDeviceLists中 ?????????????????? else { ??????????????????? // add the new entry to the list ??????????????????? pdl->pNext = gpDeviceLists; ??????????????????? gpDeviceLists = pdl; ??????????????? } ? ??????????????? // update the index ??????????????? dwIndex++; ??????????? } ?????? ?} while(dwStatus == ERROR_SUCCESS); ? ??????? // check for abnormal termination of the loop ??????? if(dwStatus != ERROR_NO_MORE_ITEMS) { ??????????? fOk = FALSE; ??????? } ? ??????? // close the registry handle ??????? RegCloseKey(hk); ??? } ? // add the default list last // 通用設備類留在最后進行初始化,為什么? // 主要是為了讓通用設備類保持在gpDeviceLists的最前面,利于后面的處理 ??? if(fOk) { ??????? fOk = FALSE; ??????? pdl = DeviceListCreate(&idGenericPMDeviceClass); ??????? if(pdl != NULL) { ??????????? if(PlatformDeviceListInit(pdl) == FALSE) { ??????????????? PMLOGMSG(ZONE_INIT || ZONE_WARN, ??????????????????? (_T("%s: PlatformDeviceListInit() failed for default class/r/n"), ??????????????????? pszFname)); ??????????????? DeviceListDestroy(pdl); ??????????? } else { ??????????????? pdl->pNext = gpDeviceLists; ??????????????? gpDeviceLists = pdl; ??????????????? fOk = TRUE; ??????????? } ??????? } ??? } ? ??? // clean up if necessary ??? if(!fOk) { ??????? PMLOGMSG(ZONE_WARN, (_T("%s: error during list initialization/r/n"), ??????????? pszFname)); ??????? while(gpDeviceLists != NULL) { ??????????? pdl = gpDeviceLists; ??????????? gpDeviceLists = pdl->pNext; ??????????? pdl->pNext = NULL; ??????????? DeviceListDestroy(pdl); ??????? } ??? } ? ??? return fOk; } |
?????? 接下來PmInit會去創建線程PnpThreadProc,該線程非常重要,它主要來檢測系統中地新加載的設備。雖然其名字是PNP,但是其服務對象不僅僅是PNP設備,迷惑了我十幾分鐘。
PnpThreadProc的優先級可以通過注冊表項PnPPriority256去進行配置,如果沒有配置,將采用默認的249。
| // this thread waits for power manageable devices to be announced.? When // they arrive they are added to the PM's list of devices and initialized // appropriately.? If a device goes away, its entry will be removed // from the list. DWORD WINAPI PnpThreadProc(LPVOID lpvParam) { ??? DWORD dwStatus; ??? HANDLE hnGeneric = NULL; ??? HANDLE hevReady = (HANDLE) lpvParam; ??? HANDLE hEvents[MAXIMUM_WAIT_OBJECTS]; ??? DWORD dwNumEvents = 0; ??? BOOL fDone = FALSE; ??? BOOL fOk; ??? INT iPriority; ??? PDEVICE_LIST pdl; ??? SETFNAME(_T("PnpThreadProc")); ? ??? PMLOGMSG(ZONE_INIT, (_T("+%s: thread 0x%08x/r/n"), pszFname, GetCurrentThreadId())); ? ??? // set the thread priority ??? if(!GetPMThreadPriority(_T("PnPPriority256"), &iPriority)) { ??????? iPriority = DEF_PNP_THREAD_PRIORITY; ??? } ??? CeSetThreadPriority(GetCurrentThread(), iPriority); ? ??? // first list entry is the exit event ??? hEvents[dwNumEvents++] = ghevPmShutdown; ? ??? // set up device notifications ??? for(pdl = gpDeviceLists; pdl != NULL && dwNumEvents < dim(hEvents); pdl = pdl->pNext) { ??????? hEvents[dwNumEvents++] = pdl->hMsgQ; ???????? // 有幾個GUID類別,就申請幾個通知 ??????? pdl->hnClass = RequestDeviceNotifications(pdl->pGuid, pdl->hMsgQ, TRUE); ??????? if(pdl->hnClass == NULL) { ??????????? PMLOGMSG(ZONE_WARN, (_T("%s: RequestDeviceNotifications() failed %d/r/n"), ??????????????? pszFname, GetLastError())); ??????? } ??? } ??? DEBUGCHK(dwNumEvents > 1); ? ??? // we're up and running ??? SetEvent(hevReady); ? ??? // wait for new devices to arrive ??? while(!fDone) { ??????? dwStatus = WaitForMultipleObjects(dwNumEvents, hEvents, FALSE, INFINITE); ?? ?????if(dwStatus == (WAIT_OBJECT_0 + 0)) { ??????????? PMLOGMSG(ZONE_WARN, (_T("%s: shutdown event set/r/n"), pszFname)); ??????????? fDone = TRUE; ??????? } else if(dwStatus > WAIT_OBJECT_0 && dwStatus <= (WAIT_OBJECT_0 + MAXIMUM_WAIT_OBJECTS)) { ?????? ?????dwStatus -= WAIT_OBJECT_0; ????????????? // 收到通知就就對特定GUID設備的電源狀態進行獲取 ??????????? fOk = ProcessPnPMsgQueue(hEvents[dwStatus]); ??????????? if(!fOk) { ??????????????? PMLOGMSG(ZONE_WARN, (_T("%s: ProcessPnPMsgQueue(0x%08x) failed/r/n"), pszFname, ???????????????? ???hEvents[dwStatus])); ??????????? } ??????? } else { ??????????? PMLOGMSG(ZONE_WARN, (_T("%s: WaitForMultipleObjects() returned %d, status is %d/r/n"), ??????????????? pszFname, dwStatus, GetLastError())); ??????????? fDone = TRUE; ??????????? break; ? ??????} ??? } ? ??? // release resources ??? for(pdl = gpDeviceLists; pdl != NULL; pdl = pdl->pNext) { ??????? if(pdl->hnClass != NULL) StopDeviceNotifications(pdl->hnClass); ??? } ? ??? // all done ??? PMLOGMSG(ZONE_INIT | ZONE_WARN, (_T("-%s: exiting/r/n"), pszFname)); ??? return 0; } |
?????? 可以上面可以看到,線程PnpThreadProc只會偵測鏈表gpDeviceLists中創建的GUID類設備的通知,而gpDeviceLists是由函數DeviceListsInit()中進行初始化的。也就是說,PM最終所能夠識別的設備是那些在注冊表[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet
/Control/Power/Interfaces]下定義的GUID類,這也是為什么設備支持電源管理的話必須定義IClass。
?????? 當然,理論上來講,你可以修改注冊表,添加一種新的GUID類,并ReWrite PM的代碼,使其支持你所添加的GUID類設備。
2.PM獲取新加載設備所支持電源狀態過程
?????? 從上面函數PnpThreadProc()中可以看到,當偵測到有新設備通知發出來后,將會調用函數ProcessPnPMsgQueue()。
?????? 函數ProcessPnPMsgQueue()完成的功能是獲取設備所支持的電源狀態,方式是調用MDD層提供的函數RequestStreamDevice或者RequestDisplayDevice。再說的具體一點就是,分別調用到設備驅動中的DeviceIoControl和ExtEscape。
?????? 請看函數ProcessPnPMsgQueue()的代碼:
| // 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 ???? // 到DEVICE_LIST鏈表中查詢當前設備所在的GUID類對應的DEVICE_LIST指針 ??? PDEVICE_LIST pdl = GetDeviceListFromClass(guidDevClass); ??? ??? // did we find the list? ??? if(pdl != NULL) { ??????? // check for duplicates ???????? // 到當前設備所對應的DEVICE_LIST鏈表中查詢是否在名字為pszName的設備 ??????? PDEVICE_STATE pds = DeviceStateFindList(pdl, pszName); ??????? ??????? // create the device if it doesn't already exist ???????? // 如果不存在,則創建一個 ??????? if(pds == NULL) { ??????????? BOOL fOk = FALSE; ????????????? // 為當前設備創建一個DEVICE_STATE節點 ??????????? 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 ?????????????????? // 將當前設備的DEVICE_STATE加入到guidDevClass對應的DEVICE_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); ?????????????????????? // 獲取設備的操作Handle,這里比較重要,調用的其實是MDD層中首先的函數OpenStreamDevice或者OpenDisplayDevice ??????????????????? 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 ???????????????????????????????? // 有點意思了,呵呵,調用IOCTL_POWER_CAPABILITIES獲取設備所支持的電源狀態這里比較重要,調用的其實是MDD層中首先的函數RequestStreamDevice或者RequestDisplayDevice,對于這兩類設備來說,分別調用到設備驅動中的DeviceIoControl和ExtEscape ??????????????????????????? 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 ???????????????????????????????? // 幫助文檔中提到,這里的意思是: ???????????????????????????????? // Set to POWER_CAP_PARENT bit if the device would like to receive an IOCTL_REGISTER_POWER_RELATIONSHIP call after initialization ???????????????????????????????? // BSP中并沒有使用,應該不用關注 ??????????????????????????? if((pds->caps.Flags & POWER_CAP_PARENT) != 0) { ??????????????????????????????? pds->pInterface->pfnRequestDevice(pds->hDevice, IOCTL_REGISTER_POWER_RELATIONSHIP, ??????????????????????????????????? NULL, 0, NULL, 0, NULL); ??????????????????????????? } ??????????????????????? } ??????????????????? } ??????????????? } ??????????????? ??????????????? // have we read all the configuration information we need from ??????????????? // the new device ??????????????? if(!fOk) { ??????????????????? // no, delete the device ??????????????????? DeviceStateRemList(pds); ??????????????? } else { ??????????????????? // See if the device supports multiple handles.? Power manageable devices ??????????????????? // should allow multiple open handles, but if they don't we will have to open ??????????????????? // one before each access. ??????????????????? HANDLE hDevice = pds->pInterface->pfnOpenDevice(pds); ??????????????????? if(hDevice == INVALID_HANDLE_VALUE) { ??????????????? ????????PMLOGMSG(ZONE_WARN, (_T("%s: WARNING: '%s' does not support multiple handles/r/n"), ??????????????????????????? pszFname)); ??????????????????????? pds->pInterface->pfnCloseDevice(pds->hDevice); ??????????????????????? pds->hDevice = INVALID_HANDLE_VALUE; ??????????????????? } else { ??????????????????????? // close the second handle, since we don't need it ??????????????????????? pds->pInterface->pfnCloseDevice(hDevice); ??????????????????? } ??????????????????? ??????????????????? // initialize the new device's power state variables ?????????????????????? // 這里就不用說了,更新電源狀態,呵呵 ??????????????????? UpdateDeviceState(pds); ??????????????? } ??????????? } ??????? } ??????? ??????? // we are done with the device pointer ??????? if(pds != NULL) { ??????????? DeviceStateDecRef(pds); ??????? } ??? } else { ??????? PMLOGMSG(ZONE_WARN, (_T("%s: class for device '%s' not supported/r/n"), ??????????? pszFname, pszName)); ??? } } |
3.IClass對AP層面的影響
?????? 這個比較簡單,可以參照Help文檔,如下:
| Beginning with Windows CE .NET 4.10, power-manageable devices can belong to varying device classes. These device classes consist both of predefined classes as well as custom device classes. The Power Manager APIs that accept device names can also accept class-qualified device names. For example, each of the following names is a valid device name: ·???????????????? COM1: ·???????????????? {A32942B7-920C-486b-B0E6-92A702A99B35}/COM1: ·???????????????? {98C5250D-C29A-4985-AE5F-AFE5367E5006}/CISCO1 ·???????????????? {8DD679CE-8AB4-43c8-A14A-EA4963FAA715}/DSK1: If a class does not qualify a device name, the device is assumed to belong to the default device class. For example, the names COM1: and {A32942B7-920C-486b-B0E6-92A702A99B35}/COM1: are equivalent. |
?????? 可以看到,AP調用PM的API嘗試去獲取或者改變設備的電源狀態的時候,需要傳入爭取地Device name,如果傳入的Device name不包含IClass的話,系統將其認為是默認的IClass類,也就是{A32942B7-920C-486b-B0E6-92A702A99B35}。
?????? 由于SDK中會有GUID類的定義,所以AP中調用PM API的時候最好能夠傳入完整的Device name。
?
?
總結
以上是生活随笔為你收集整理的IClass与电源管理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MMU及PTS说明
- 下一篇: 从Var Tick角度来对CE电源管理