Wince Battery driver

最近调了wince battery driver, 对电池驱动有了一点点了解,如下:

1.Windows CE电池驱动属于分层驱动,由MDD层和PDD层组成。微软给我们的代码在D:/WINCE600/PUBLIC/COMMON/OAK/DRIVERS/BATTDRVR 目录下,该目录MDD文件夹是MDD 代码,一般的我们都不用动,直接引用即可。而PDD文件夹下的sbattif.c 是PDD的框架代码,我们可以直接靠过来,针对具体硬件添加代码。

2.MDD层函数包括:Init、Deinit、Open、Close、Read、Write、Seek、PowerDown、PowerUp、IOControl。我主要分析一下Init。DWORD Init( PVOID Context ) { DWORD dwHandle = 0; // assume failure SETFNAME(_T("BattDrvr: Init")); DEBUGMSG(ZONE_INIT, (_T("%s: invoked w/ context 0x%08x/r/n"), pszFname, Context)); // have we already been loaded? if(ghevResume == NULL) { // get a handle to our API event HANDLE hevReady = OpenEvent(EVENT_ALL_ACCESS, FALSE, BATTERY_API_EVENT_NAME); if(hevReady == NULL) { DEBUGMSG(ZONE_ERROR || ZONE_INIT, (_T("%s: fatal error: can't open API event/r/n"), pszFname)); goto done; } // no, initialize global variables InitializeCriticalSection(&gcsBattery); InitializeCriticalSection(&gcsPddBuffer); gpfnBatteryPddIOControl = NULL; // must be initialized by the PDD gdwPddBufferSize = sizeof(SYSTEM_POWER_STATUS_EX2); gpPddBuffer = NULL; gpPddBufferTemp = NULL; ghevResume = CreateEvent(NULL, FALSE, FALSE, NULL); if(ghevResume == NULL) { DEBUGMSG(ZONE_ERROR || ZONE_INIT, (_T("%s: CreateEvent() failed/r/n"), pszFname)); } else { if(!BatteryPDDInitialize(Context)) { DEBUGMSG(ZONE_ERROR || ZONE_INIT, (_T("%s: BatteryPDDInitialize() failed/r/n"), pszFname)); } else { HKEY hk; DWORD dwLen; // init defaults gBatteryContext.dwPollTimeout = DEF_BATTERYPOLLTIMEOUT; gBatteryContext.iPriority = 249; // THREAD_PRIORITY_HIGHEST memset(&gBatteryContext.st, 0xFF, sizeof(gBatteryContext.st)); // get my thread priority configuration hk = OpenDeviceKey(Context); if(hk != NULL) { DWORD dwValue, dwType, dwSize, dwStatus; // get the thread priority dwSize = sizeof(dwValue); dwStatus = RegQueryValueEx(hk, _T("PollPriority256"), NULL, &dwType, (LPBYTE) &dwValue, &dwSize); if(dwStatus == ERROR_SUCCESS && dwType == REG_DWORD) { gBatteryContext.iPriority = (INT) dwValue; } // get the polling interval dwSize = sizeof(dwValue); dwStatus = RegQueryValueEx(hk, _T("PollInterval"), NULL, &dwType, (LPBYTE) &dwValue, &dwSize); if(dwStatus == ERROR_SUCCESS && dwType == REG_DWORD) { gBatteryContext.dwPollTimeout = dwValue; } // get the Pdd buffer size dwSize = sizeof(dwValue); dwStatus = RegQueryValueEx(hk, _T("PddBufferSize"), NULL, &dwType, (LPBYTE) &dwValue, &dwSize); if(dwStatus == ERROR_SUCCESS && dwType == REG_DWORD) { if( dwValue > gdwPddBufferSize ) { gdwPddBufferSize = dwValue; } } RegCloseKey(hk); } gpPddBuffer = (BYTE*)LocalAlloc( LPTR, gdwPddBufferSize ); if( gpPddBuffer == NULL ) { DEBUGMSG(ZONE_ERROR || ZONE_INIT, (_T("%s: BatteryPDDInitialize() failed to allocate the Pdd buffer./r/n"), pszFname)); goto done; } gpPddBufferTemp = (BYTE*)LocalAlloc( LPTR, gdwPddBufferSize ); if( gpPddBufferTemp == NULL ) { DEBUGMSG(ZONE_ERROR || ZONE_INIT, (_T("%s: BatteryPDDInitialize() failed to allocate the Pdd temp buffer./r/n"), pszFname)); goto done; } // initialize battery update variables dwLen = BatteryAPIGetSystemPowerStatusEx2 (&gBatteryContext.st, sizeof(gBatteryContext.st), TRUE); DEBUGCHK(dwLen == sizeof(gBatteryContext.st)); // start the battery monitor/resume thread ghtBattery = CreateThread(NULL, 0, BatteryThreadProc, &gBatteryContext, 0, NULL); if(ghtBattery == NULL) { DEBUGMSG(ZONE_ERROR || ZONE_INIT, (_T("%s: CreateThread() failed %d/r/n"), pszFname, GetLastError())); } else { // notify the world that we're up and running SetEvent(hevReady); CloseHandle(hevReady); // return success dwHandle = 1; } } } done: // clean up if something went wrong if(dwHandle == 0) { if(gpPddBuffer != NULL) { LocalFree( gpPddBuffer ); gpPddBuffer = NULL; } if(gpPddBufferTemp != NULL) { LocalFree( gpPddBufferTemp ); gpPddBufferTemp = NULL; } if(ghtBattery != NULL) { DEBUGCHK(ghevResume != NULL); gfExiting = TRUE; SetEvent(ghevResume); WaitForSingleObject(ghtBattery, INFINITE); CloseHandle(ghtBattery); ghtBattery = NULL; } if(ghevResume != NULL) { CloseHandle(ghevResume); ghevResume = NULL; } DeleteCriticalSection(&gcsBattery); DeleteCriticalSection(&gcsPddBuffer); } } DEBUGMSG(ZONE_INIT, (_T("%s: returning %d/r/n"), pszFname, dwHandle)); return dwHandle; }

 
1.判断ghevResume事件是否为NULL,条件成立表示驱动还未加载继续执行,否则表示驱动已经加载跳出执行。
2.打开一个名为“SYSTEM/BatteryAPIsReady”的事件。“SYSTEM/BatteryAPIsReady”事件在注册表HKEY_LOCAL_MACHINE/System/Events下面,在内核初始化的时候由filesys.exe创建。
[HKEY_LOCAL_MACHINE/System/Events]
       "SYSTEM/BatteryAPIsReady"="Battery Interface APIs"
3.创建ghevResume事件。
4.调用BatteryPDDInitialize初始化电池信息,调用PDD层代码。
5.  打开注册表,获取轮询查询电池状态时间间隔,其默认的时间间隔为:
#define DEF_BATTERYPOLLTIMEOUT          (5*1000)         // in milliseconds
注册表设置的时间间隔:
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/Battery]
       "PollInterval"=dword:3e8  ;in milliseconds
       "BattCalibrationPoint"=dword:7
       "BattCalibrationData"=hex:59,03,4b,03,32,03,1c,03,09,03,f5,02,e0,02
6.调用BatteryAPIGetSystemPowerStatusEx2函数更新电池最新信息。BatteryAPIGetSystemPowerStatusEx2函数主要调用BatteryPDDGetStatus函数获取电池信息,这个函数在PDD层实现。
7.创建一个电池监控线程,处理系统resume消息,定时查询电池状态并通知系统。
8.设置“SYSTEM/BatteryAPIsReady”事件,通知系统电池驱动已经正常运行。

3.    PDD层函数主要包括:BatteryPDDInitialize、BatteryPDDDeinitialize、BatteryPDDResume、BatteryPDDPowerHandler、BatteryPDDGetStatus、BatteryPDDGetLevels、BatteryPDDSupportsChangeNotification 等函数,个人觉得最重要的事BatteryPDDInitialize和BatteryPDDGetStatus。

下面是我的BatteryPDDInitialize 代码:BOOL WINAPI BatteryPDDInitialize(LPCTSTR pszRegistryContext) { BOOL fOk = TRUE; SYSTEM_POWER_STATUS_EX2 sps; WORD wMainLevels = 3, wBackupLevels = 0; BOOL fSupportsChange = FALSE; SETFNAME(_T("BatteryPDDInitialize")); DEBUGCHK(ghMutex == NULL); DEBUGCHK(ghFileMap == NULL); DEBUGCHK(gpStatus == NULL); DEBUGCHK(pszRegistryContext != NULL); DEBUGMSG(DBG_ATLAS_ZONE_INIT, (TEXT("%s:%d:+++++++++++++++/r/n"),_T(__FUNCTION__),__LINE__)); //----- 1. Map System Register if(!CspRegMap(TRUE)) { RETAILMSG(DBG_ATLAS_ZONE_ERROR, (TEXT("%s:%d:Failed to Map register!/r/n"),_T(__FUNCTION__),__LINE__)); goto _ERR_BATT; } //----- 2. Batt IC Init if(!BspBattInit(pszRegistryContext)) { RETAILMSG(DBG_ATLAS_ZONE_ERROR, (TEXT("%s:%d:BspBattInit Error!/r/n"),_T(__FUNCTION__),__LINE__)); goto _ERR_BATT; } //----- 3. Batt ADC Init if(!BspBattADCInit(pszRegistryContext)) { RETAILMSG(DBG_ATLAS_ZONE_ERROR, (TEXT("%s:%d:BspBattPMInit Error!/r/n"),_T(__FUNCTION__),__LINE__)); goto _ERR_BATT; } //----- 4. Batt PM Init if(!BspBattPMInit(pszRegistryContext)) { RETAILMSG(DBG_ATLAS_ZONE_ERROR, (TEXT("%s:%d:BspBattPMInit Error!/r/n"),_T(__FUNCTION__),__LINE__)); goto _ERR_BATT; } //----- 5. intialize the battery status structure -- assume AC power, no battery info (get from Wince6.0 Private Code) sps.ACLineStatus = AC_LINE_ONLINE; sps.BatteryFlag = BATTERY_FLAG_HIGH; sps.BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN; sps.Reserved1 = 0; sps.BatteryLifeTime = BATTERY_LIFE_UNKNOWN; sps.BatteryFullLifeTime = BATTERY_LIFE_UNKNOWN; sps.Reserved2 = 0; sps.BackupBatteryFlag = BATTERY_FLAG_UNKNOWN; sps.BackupBatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN; sps.Reserved3 = 0; sps.BackupBatteryLifeTime = BATTERY_LIFE_UNKNOWN; sps.BackupBatteryFullLifeTime = BATTERY_LIFE_UNKNOWN; sps.BatteryChemistry = BATTERY_CHEMISTRY_UNKNOWN; sps.BatteryVoltage = 0; sps.BatteryCurrent = 0; sps.BatteryAverageCurrent = 0; sps.BatteryAverageInterval = 0; sps.BatterymAHourConsumed = 0; sps.BatteryTemperature = 0; sps.BackupBatteryVoltage = 0; g_PreACLineStatus = sps.ACLineStatus; //----- 6. Allocate resources (get code from Wince6.0 Private Code) if((ghMutex = CreateMutex(NULL, FALSE, BATTERY_FILE_MUTEX)) == NULL) { /* DEBUGMSG(DBG_ATLAS_ZONE_ERROR || DBG_ATLAS_ZONE_INIT , (_T("%s: Could not aquire battery info file mutex handle/n"), pszFname)); */ fOk = FALSE; } else { HINSTANCE hiCoreDll = NULL; BOOL fNewMapping = TRUE; // get pointers to file-mapping functions hiCoreDll = LoadLibrary(_T("coredll.dll")); if(hiCoreDll != NULL) { gpfnCreateFileMappingW = (PFN_CreateFileMappingW) GetProcAddress((HMODULE) hiCoreDll, _T("CreateFileMappingW")); gpfnMapViewOfFile = (PFN_MapViewOfFile) GetProcAddress((HMODULE) hiCoreDll, _T("MapViewOfFile")); gpfnUnmapViewOfFile = (PFN_UnmapViewOfFile) GetProcAddress((HMODULE) hiCoreDll, _T("UnmapViewOfFile")); } FreeLibrary(hiCoreDll); // we're already linked to coredll // serialize access to the mapping file LockBattery(); // create the mapping if(gpfnCreateFileMappingW == NULL ) { // no file mapping, use a global variable static BATTERY_STATUS sBatteryStatus; gpStatus = &sBatteryStatus; RETAILMSG(1,(TEXT("no file mapping, use a global variable!/r/n"))); } else if((ghFileMap = gpfnCreateFileMappingW((HANDLE)INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(BATTERY_STATUS), BATTERY_STATUS_FILE)) == NULL) { RETAILMSG(1,(TEXT("Could not create file mapping for battery info file!/r/n"))); /* DEBUGMSG(ZONE_ERROR || ZONE_PDD || ZONE_INIT, (_T("%s: Could not create file mapping for battery info file/n"), pszFname)); */ fOk = FALSE; } else { // is this a new mapping? if(GetLastError() == ERROR_ALREADY_EXISTS) { fNewMapping = FALSE; } // map the object into our address space if(gpfnMapViewOfFile == NULL || (gpStatus = (PBATTERY_STATUS) gpfnMapViewOfFile(ghFileMap, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(BATTERY_STATUS))) == NULL) { /* DEBUGMSG(ZONE_ERROR || ZONE_PDD || ZONE_INIT, (_T("Could not map view of battery info file into process address space/n"), pszFname)); */ fOk = FALSE; } } // should we initialize our structure? if(fOk && fNewMapping) { // initialize the memory mapped object memcpy(&gpStatus->sps, &sps, sizeof(gpStatus->sps)); gpStatus->fSupportsChange = fSupportsChange; gpStatus->fChanged = FALSE; gpStatus->wMainLevels = wMainLevels; gpStatus->wBackupLevels = wBackupLevels; } // allow access to the battery buffer UnlockBattery(); } //----- 7. clean up if necessary (get from Wince6.0 Private Code) if(!fOk) { if(gpStatus != NULL && gpfnUnmapViewOfFile != NULL) gpfnUnmapViewOfFile(gpStatus); if(ghFileMap != NULL) CloseHandle(ghFileMap); if(ghMutex != NULL) CloseHandle(ghMutex); gpStatus = NULL; ghFileMap = NULL; ghMutex = NULL; } //----- 8. Register a function to receive custom IOCTLs gpfnBatteryPddIOControl = BatteryPddIOControl; DEBUGMSG(DBG_ATLAS_ZONE_INIT,(TEXT("%s:%d:----------------/r/n"),_T(__FUNCTION__),__LINE__)); return fOk; _ERR_BATT: RETAILMSG(DBG_ATLAS_ZONE_ERROR,(TEXT("+Battery ERROR OR UNKNOWN STATUS... /r/n"))); BspBattPMDeinit(); BspBattADCDeinit(); BspBattDeinit(); CspRegUnMap(); SetLastError(ERROR_NOT_SUPPORTED); DEBUGMSG(DBG_ATLAS_ZONE_INIT,(TEXT("%s:%d:----------------/r/n"),_T(__FUNCTION__),__LINE__)); return FALSE; }

主要是硬件初始化和填充电池信息结构体SYSTEM_POWER_STATUS_EX2 ;电池获得电量是通过读ADC寄存器的值再转化为电量百分比,具体硬件不同可能实现的方法有所不同;

BatteryPDDGetStatus 主要是检查电池当前的状态,重新更新SYSTEM_POWER_STATUS_EX2 结构体,可以添加电池低电报警功能在这里,控制开机电池最低电量!

你可能感兴趣的:(thread,function,File,null,WinCE,variables)