📄 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.
//
//
// 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
//
#define BATTERY_DATA_DEF // global battery driver variables defined here
#include <battimpl.h>
#include <nkintr.h>
#include <devload.h>
#include <pmpolicy.h>
#include <pm.h>
#include ".\inc\power.h"
#include ".\inc\charge.h"
#include "hw_lib.h"
extern void SaveQAcc(void);
extern void ShowPicture(void);
#define DEF_BATTERYPOLLTIMEOUT 30000//300000 // 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;
// global variables
CRITICAL_SECTION gcsBattery;
PFN_BATTERY_PDD_IOCONTROL gpfnBatteryPddIOControl;
HANDLE ghevResume;
HANDLE ghtBattery;
BOOL gfExiting;
BATTERY_CONTEXT gBatteryContext;
// 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);
PREFAST_DEBUGCHK(pbc != NULL);
// 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;
}
// 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;
}
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;
}
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_POWER_SET :
if(pOutBuf != NULL && OutBufLen == sizeof(CEDEVICE_POWER_STATE) && pdwBytesTransferred != NULL)
{
// allow a set to any state, but if requested to go to D3, go to D4 instead.
// Since our device doesn't touch any hardware, we just set its CurrentDx
// member to update the power setting. A real device driver would probably
// need to touch hardware.
__try {
CEDEVICE_POWER_STATE NewDx = *(PCEDEVICE_POWER_STATE) pOutBuf;
if(VALID_DX(NewDx))
{
if(NewDx > D0)
{
//close backlight
// PM_BackLight(OFF);
RETAILMSG(1, (_T("IOCTL_POWER_SET:Close bklight\r\n")));
}
else
{
//open backlight
// PM_BackLight(ON);
RETAILMSG(1, (_T("IOCTL_POWER_SET:Open bklight\r\n")));
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER) {
DEBUGMSG(ZONE_IOCTL, (_T("%s: exception in ioctl\r\n")));
}
}
break;
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 + -