wince5.0電池驅動樣本分析

       battdrvr驅動是分層驅動,battdrvr.cMDD層的,微軟已經爲我們搭好了構架,我們一般不需要修改,我們要實現的是PDD層的代碼,PPD層的代碼在sbattif.c裏面實現。

       首先分析MDD層的代碼。首先定義了一個BATTERY_CONTEXT結構來存儲電池信息,其中,dwPollTimeout是循環更新電池信息線程的最大阻塞時間,iPriority是這個線程的優先級,st存儲系統電源狀態信息,它是一個SYSTEM_POWER_STATUS_EX2結構體,可以在MSDN裏面查到它的原型。然後聲明一些全局變量,gcsBattery是臨界區,然後定義了一個PFN_BATTERY_PDD_IOCONTROL函數,這個函數的參數說明也可以在MSDN裏面查閱,聲明一個句柄ghevResume來控制BatteryThreadProc的阻塞,而ghtBattery句柄是用來指示

BatteryThreadProc創建是否成功的,接下來聲明一個BOOL類型的變量gfExiting判斷是否卸載驅動,最後聲明一個代表電池的信息的變量gBatteryContext

       我們開始分析第一個流接口函數Init,在battdrvr.reg中有這樣一句:"Flags"=dword:8        ; DEVFLAGS_NAKEDENTRIES

所以,這幾個流接口函數前面都省略了前綴BAT

Init函數首先判斷ghevResume是否爲空,如果爲空則代表驅動尚未被加載過,我們在if語句裏面需要做一些初始化的工作。如果需要使用battery函數,就要SYSTEM/BatteryAPIsReady事件信號被激活,這個事件在Battery.h裏面被定義爲BATTERY_API_EVENT_NAME。所以Init調用OpenEvent打開這個事件,並返回這個事件的句柄給hevReady。然後函數InitializeCriticalSection初始化臨界區gcsBatterygpfnBatteryPddIOControl被定義爲NULL表示MDD層不負責初始化這個變量,交給PDD層完成這個工作。然後創建事件初始化ghevResume。接着把Context傳遞給PDD層函數BatteryPDDInitialize,由BatteryPDDInitialize來做進一步的和硬件相關的初始化工作。接着初始化代表電池信息的gBatteryContext。然後調用OpenDeviceKey函數獲得Context註冊表鍵值的句柄,接下來依次獲得線程的優先級及其阻塞時間。再調用BatteryAPIGetSystemPowerStatusEx2函數初始化電池更新。在if的最後調用CreateThread函數開始BatteryThreadProc線程並將gBatteryContext傳遞給它,同時激活SYSTEM/BatteryAPIsReady事件信號。在done裏面有這樣一句:

WaitForSingleObject(ghtBattery, INFINITE);

也許意思是讓定時更新電池信息的線程即BatteryThreadProc執行完畢。

       接下來我們就來分析一下這個定時更新電池信息的線程BatteryThreadProcInit傳給pvParam的參數BATTERY_CONTEXT類型的指針,所以我們需要把pvParam轉換爲PBATTERY_CONTEXT。調用函數CeSetThreadPriority來設置當前進程的優先級。PowerPolicyNotify函數的頭文件是pmpolicy.h,第一個參數決定了第二個參數必須設置爲0,這個函數通知電源管理器更新電池狀態。接下來調用WaitForSingleObject函數定時循環這個線程,如果dwStatusWAIT_TIMEOUT,即到時間需要更新電池信息了,LOCKBATTERYUNLOCKBATTERYsbattif.c裏面定義的,保證了兩者時間的代碼是CPU獨佔的,在這個獨佔的時間內,BatteryThreadProc調用BatteryAPIGetSystemPowerStatusEx2更新電池信息,然後判斷是不是有更新,有則更新pbc並通知電源管理器更新電池狀態;如果dwStatusWAIT_OBJECT_0,說明系統繼續了這個線程,那麼我們就重新啓動這個這個時間表,BatteryAPIStopwatch函數在battapi.c裏面實現,BatteryPDDResume用於調試,我們不用關心。

       下面還有一個重要的流接口函數IOControl,我們簡單對其分析。

       如果IOControl的第二個參數爲IOCTL_BATTERY_GETSYSTEMPOWERSTATUSEX2,判斷是否有寫數據,如果有則調用BatteryAPIGetSystemPowerStatusEx2函數更新電池信息;如果IoctlIOCTL_BATTERY_GETSYSTEMPOWERSTATUSEX,操作與前面相似;如果IoctlIOCTL_BATTERY_GETLIFETIMEINFOIOControl函數調用BatteryAPIGetLifeTimeInfo來獲取PBATTERYLIFETIMEINFO信息,這個函數在battapi.c裏面定義;如果ioctlIOCTL_BATTERY_GETLEVELSIOControl調用BatteryPDDGetLevels來獲取level值;如果ioctlIOCTL_BATTERY_SUPPORTSCHANGENOTIFICATIONIOControl調用BatteryPDDSupportsChangeNotification來獲知電源信息更新與否;如果ioctlIOCTL_BATTERY_NOTIFYOFTIMECHANGEIOControl調用BatteryAPINotifyOfTimeChange函數。

       爲了防止編譯器關於爲引用參數的警告,我們可以使用宏UNREFERENCED_PARAMETER來展開傳遞參數,沒有實際作用,所以我們不用再分析其他流接口函數。

       至此,wince5.0電池樣本驅動的MDD層就分析完了,下面簡單分析PDD層代碼。首先定義了由ghMutex互斥信號量決定的兩個函數LockBatteryUnlockBattery。我們主要分析下BatteryPDDInitialize函數,這個函數先初始化電池狀態結構體SYSTEM_POWER_STATUS_EX2變量sps。然後打開註冊表,查詢各種信息並保存。接着,創建信號量,獲取文件映射的指針。最後完成文件映射工作。其他函數都比較容易讀懂了。

      

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章