📄 battdrvr.c
字号:
/*******************************************************************************
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*
* Use of this source code is subject to the terms of the Microsoft end-user
* license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
* If you did not accept the terms of the EULA, you are not authorized to use
* this source code. For a copy of the EULA, please see the LICENSE.RTF on your
* install media.
*
* *//**
* @file battdriver.c
* @brief Sample Battery Driver.
*
* This module contains a sample battery driver for windows CE. It
* exposes its interface to the system via a set of IOCTLs which device.exe
* invokes on its behalf when one of the battery APIs are invoked. The
* following APIs are modeled in this way:
*
* GetSystemPowerStatusEx
* GetSystemPowerStatusEx2
* BatteryGetLifeTimeInfo
* BatteryDrvrSupportsChangeNotification
* BatteryDrvrGetLevels
* BatteryNotifyOfTimeChange
*
* When it initializes, this driver is responsible for setting the battery
* API ready event to indicate it is ready to receive IOCTLs in response
* to these APIs.
*
* This example driver comes with a stubbed-out implementation of the
* low-level battery interfaces. OEMs that wish to produce their own
* battery driver can write a module containing the low-level entry points
* in their platform and simply link with the library containing this module.
* The linker will bring in the rest of the driver as an MDD.
*
* The low-level interfaces necessary that must be overridden to produce
* a platform-specific PDD are:
*
* BatteryPDDInitialize
* BatteryPDDDeinitialize
* BatteryPDDGetStatus
* BatteryPDDGetLevels
* BatteryPDDSupportsChangeNotification
* BatteryPDDPowerHandler
* BatteryPDDResume
*
* @version $Id$
*
******************************************************************************/
/*
* Include files
*/
#define BATTERY_DATA_DEF /** global battery driver variables defined here */
#include <battimpl.h>
#include <nkintr.h>
#include <devload.h>
#include <pmpolicy.h>
/*
* Global Definitions
*/
#define DEF_BATTERYPOLLTIMEOUT 500 /** in milliseconds */
/** this structure contains startup parameters for the battery monitor
thread */
typedef struct _batteryContext_tag {
DWORD dwPollTimeout;
int iPriority;
SYSTEM_POWER_STATUS_EX2 st;
} BATTERY_CONTEXT, * PBATTERY_CONTEXT;
CRITICAL_SECTION gcsBattery;
PFN_BATTERY_PDD_IOCONTROL gpfnBatteryPddIOControl;
HANDLE ghevResume;
HANDLE ghtBattery;
BOOL gfExiting;
BATTERY_CONTEXT gBatteryContext;
/******************************************************************************
* Function: BatteryThreadProc *//**
*
* @brief This thread handles resume notifications for the battery driver. It
* will also poll the battery for status updates at regular intervals,
* depending on the poll interval configuration in the registry.
*
*****************************************************************************/
DWORD WINAPI BatteryThreadProc(PVOID pvParam)
{
BOOL fDone = FALSE;
BOOL fOk;
PBATTERY_CONTEXT pbc = (PBATTERY_CONTEXT) pvParam;
SETFNAME(_T("Battery: BatteryThreadProc"));
DEBUGCHK(ghevResume != NULL);
#ifndef WM_PRE_500 /* PREFAST_DEBUGCHK does not exist n 4.2 */
PREFAST_DEBUGCHK(pbc != NULL);
#endif
/** set my thread priority */
DEBUGMSG(ZONE_RESUME,
(_T("%s: thread priority is %d, timeout is %u, ID is 0x%08x\r\n"),
pszFname, pbc->iPriority, pbc->dwPollTimeout, GetCurrentThreadId()));
CeSetThreadPriority(GetCurrentThread(), pbc->iPriority);
/** tell the Power Manager to initialize its battery state */
fOk = PowerPolicyNotify(PPN_POWERCHANGE, 0);
DEBUGCHK(fOk);
/** wait for the system to resume */
while(!fDone) {
DWORD dwStatus = WaitForSingleObject(ghevResume, pbc->dwPollTimeout);
switch(dwStatus) {
case WAIT_TIMEOUT:
{
SYSTEM_POWER_STATUS_EX2 tmpst;
/** update battery status information */
LOCKBATTERY();
dwStatus = BatteryAPIGetSystemPowerStatusEx2
(&tmpst, sizeof(tmpst), TRUE);
DEBUGCHK(dwStatus == sizeof(pbc->st));
UNLOCKBATTERY();
/** has anything changed? */
if(memcmp(&tmpst, &pbc->st, sizeof(pbc->st)) != 0) {
/** yes, update our global variable and notify the power
manager */
pbc->st = tmpst;
fOk = PowerPolicyNotify(PPN_POWERCHANGE, 0);
DEBUGCHK(fOk);
}
}
break;
case WAIT_OBJECT_0: /** system has resumed */
/** GetTickCount() stops incrementing during suspends, so we can
stop and restart the battery stopwatch during resume. */
DEBUGMSG(ZONE_RESUME, (_T("%s: system has resumed\r\n"), pszFname));
BatteryAPIStopwatch(FALSE, FALSE);
BatteryAPIStopwatch(TRUE, FALSE);
BatteryPDDResume();
break;
default:
DEBUGMSG(ZONE_RESUME,
(_T("%s: WaitForSingleObject() returned %d, error %d\r\n"),
pszFname, dwStatus, GetLastError()));
fDone = TRUE;
break;
}
/** check whether we're supposed to exit */
if(gfExiting) fDone = TRUE;
}
DEBUGMSG(ZONE_RESUME, (_T("%s: exiting\r\n"), pszFname));
return 0;
}
/******************************************************************************
* Function: Init *//**
*
* @brief This routine initializes the battery driver. Since it should only
* be loaded once, it returns an error if this routine is called more
* than once.
*
*****************************************************************************/
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);
gpfnBatteryPddIOControl = NULL; // must be initialized by the PDD
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;
}
RegCloseKey(hk);
}
/** 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(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);
}
}
DEBUGMSG(ZONE_INIT, (_T("%s: returning %d\r\n"), pszFname, dwHandle));
return dwHandle;
}
/******************************************************************************
* Function: Init *//**
*
*****************************************************************************/
BOOL Deinit( DWORD dwContext )
{
DEBUGMSG(ZONE_INIT, (_T("Battery: Deinit: invoked w/ context 0x%08x\r\n"),
dwContext));
DEBUGCHK(dwContext == 1);
DEBUGCHK(ghevResume != NULL);
/** notify the PDD */
BatteryPDDDeinitialize();
/** clean up global variables */
if(ghtBattery != NULL) {
gfExiting = TRUE;
SetEvent(ghevResume);
WaitForSingleObject(ghtBattery, INFINITE);
CloseHandle(ghtBattery);
ghtBattery = NULL;
}
if(ghevResume != NULL) {
CloseHandle(ghevResume);
ghevResume = NULL;
}
DeleteCriticalSection(&gcsBattery);
DEBUGMSG(ZONE_INIT, (_T("Battery: Deinit: all done\r\n")));
return TRUE;
}
/******************************************************************************
* Function: IOControl *//**
*
*****************************************************************************/
BOOL IOControl( DWORD dwContext, DWORD Ioctl, PUCHAR pInBuf, DWORD InBufLen,
PUCHAR pOutBuf, DWORD OutBufLen, PDWORD pdwBytesTransferred )
{
DWORD dwErr = ERROR_INVALID_PARAMETER;
BOOL bRc = FALSE;
SETFNAME(_T("IOControl"));
DEBUGMSG(ZONE_FUNCTION, (_T
("%s: IOCTL:0x%x, InBuf:0x%x, InBufLen:%d, OutBuf:0x%x, OutBufLen:0x%x)\r\n"),
pszFname, Ioctl, pInBuf, InBufLen, pOutBuf, OutBufLen));
switch (Ioctl) {
case IOCTL_BATTERY_GETSYSTEMPOWERSTATUSEX2:
/** sanity check parameters */
if(pOutBuf != NULL && OutBufLen == sizeof(SYSTEM_POWER_STATUS_EX2)
&& pInBuf != NULL && InBufLen == sizeof(BOOL) && pdwBytesTransferred != NULL) {
BOOL fOk = FALSE;
BOOL fForce;
/** get the force parameter */
__try {
fForce = *((BOOL *) pInBuf);
fOk = TRUE;
}
__except(EXCEPTION_EXECUTE_HANDLER) {
DEBUGMSG(ZONE_WARN, (_T
("%s: exception reading fForce in IOCTL_BATTERY_GETSYSTEMPOWERSTATUSEX\r\n"),
pszFname));
}
/** did we get the force parameter? */
if(fOk) {
DWORD dwStatus = 0;
DEBUGCHK(fForce == TRUE || fForce == FALSE);
/** get the data */
LOCKBATTERY();
__try {
dwStatus = BatteryAPIGetSystemPowerStatusEx2(
(PSYSTEM_POWER_STATUS_EX2) pOutBuf, OutBufLen, fForce);
}
__except(EXCEPTION_EXECUTE_HANDLER) {
DEBUGMSG(ZONE_WARN, (_T
("%s: exception reading status in IOCTL_BATTERY_GETSYSTEMPOWERSTATUSEX2\r\n"),
pszFname));
dwErr = ERROR_GEN_FAILURE;
}
UNLOCKBATTERY();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -