2
* Copyright (C) 2002-2005 Mattia Dongili <malattia@linux.it>
3
* George Staikos <staikos@0wned.org>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
#include "cpufreqd_plugin.h"
27
#define ACPI_BATTERY_DIR "/proc/acpi/battery/"
28
#define ACPI_BATTERY_STATE_FILE "/state"
29
#define ACPI_BATTERY_INFO_FILE "/info"
30
#define ACPI_BATTERY_FULL_CAPACITY_FMT "last full capacity: %d %sh\n"
31
#define ACPI_BATTERY_REM_CAPACITY_FMT "remaining capacity: %d %sh\n"
41
struct battery_interval {
43
struct battery_info *bat;
46
static struct battery_info *infos = 0L;
47
static int bat_num = 0;
48
static int battery_level = 0;
50
/* int no_dots(const struct dirent *d)
52
* Filter function for scandir, returns
53
* 0 if the first char of d_name is not
56
static int no_dots(const struct dirent *d) {
57
return d->d_name[0]!= '.';
60
static struct battery_info *get_battery_info(const char *name)
63
struct battery_info *ret = NULL;
65
for (i=0; i<bat_num; i++) {
66
if (strncmp(infos[i].name, name, 32) == 0) {
74
/* static int check_battery(char *dirname)
76
* check if the battery is present and read its capacity.
77
* Returns 1 if the battery is there and has been able
78
* to read its capacity, 0 otherwise.
80
static int check_battery(struct battery_info *info) {
87
snprintf(file_name, 256, "%s%s", info->path, ACPI_BATTERY_INFO_FILE);
88
/** /proc/acpi/battery/.../info **/
89
fp = fopen(file_name, "r");
91
clog(LOG_ERR , "%s: %s\n", file_name, strerror(errno));
95
while (fgets(line, 100, fp)) {
96
if(sscanf(line, ACPI_BATTERY_FULL_CAPACITY_FMT, &tmp_capacity, ignore) == 2) {
97
info->capacity = tmp_capacity;
103
return (tmp_capacity != 0) ? 1 : 0;
107
/* static int acpi_battery_init(void)
109
* test if BATTERY dirs are present
111
static int acpi_battery_init(void) {
112
struct dirent **namelist = NULL;
115
/* get batteries paths */
116
bat_num = n = scandir(ACPI_BATTERY_DIR, &namelist, no_dots, NULL);
118
infos = malloc( bat_num*sizeof(struct battery_info) );
121
/* put the path into the array */
122
snprintf(infos[n].name, 32, "%s", namelist[n]->d_name);
123
snprintf(infos[n].path, 100, "%s%s", ACPI_BATTERY_DIR, namelist[n]->d_name);
124
infos[n].present = 0;
125
infos[n].capacity = 0;
126
/* check this battery */
127
check_battery(&(infos[n]));
129
clog(LOG_INFO, "%s battery path: %s, %s, capacity:%d\n",
130
infos[n].name, infos[n].path,
131
infos[n].present?"present":"absent", infos[n].capacity);
136
clog(LOG_INFO, "found %d battery slots\n", bat_num);
139
clog(LOG_ERR, "error, acpi_battery module not compiled or inserted (%s: %s)?\n",
140
ACPI_BATTERY_DIR, strerror(errno));
141
clog(LOG_ERR, "exiting.\n");
145
clog(LOG_ERR, "no batteries found, not a laptop?\n");
146
clog(LOG_ERR, "exiting.\n");
153
static int acpi_battery_exit(void) {
157
clog(LOG_INFO, "exited.\n");
162
* Parses entries of the form %d-%d (min-max)
164
static int acpi_battery_parse(const char *ev, void **obj) {
165
char battery_name[32];
166
struct battery_interval *ret = calloc(1, sizeof(struct battery_interval));
168
clog(LOG_ERR, "couldn't make enough room for battery_interval (%s)\n",
173
clog(LOG_DEBUG, "called with: %s\n", ev);
175
/* try to parse the %[a-zA-Z0-9]:%d-%d format first */
176
if (sscanf(ev, "%32[a-zA-Z0-9]:%d-%d", battery_name, &(ret->min), &(ret->max)) == 3) {
177
/* validate battery name and assign pointer to struct battery_info */
178
if ((ret->bat = get_battery_info(battery_name)) == NULL) {
179
clog(LOG_ERR, "non existent thermal zone %s!\n",
184
clog(LOG_INFO, "parsed %s %d-%d\n", ret->bat->name, ret->min, ret->max);
186
} else if (sscanf(ev, "%32[a-zA-Z0-9]:%d", battery_name, &(ret->min)) == 2) {
187
/* validate battery name and assign pointer to struct battery_info */
188
if ((ret->bat = get_battery_info(battery_name)) == NULL) {
189
clog(LOG_ERR, "non existent thermal zone %s!\n",
195
clog(LOG_INFO, "parsed %s %d\n", ret->bat->name, ret->min);
197
} else if (sscanf(ev, "%d-%d", &(ret->min), &(ret->max)) == 2) {
198
clog(LOG_INFO, "parsed %d-%d\n", ret->min, ret->max);
200
} else if (sscanf(ev, "%d", &(ret->min)) == 1) {
202
clog(LOG_INFO, "parsed %d\n", ret->min);
209
if (ret->min > ret->max) {
210
clog(LOG_ERR, "Min higher than Max?\n");
220
static int acpi_battery_evaluate(const void *s) {
221
const struct battery_interval *bi = (const struct battery_interval *)s;
222
int level = battery_level;
224
if (bi != NULL && bi->bat != NULL) {
225
level = bi->bat->present ? bi->bat->level : -1;
228
clog(LOG_DEBUG, "called %d-%d [%s:%d]\n", bi->min, bi->max,
229
bi != NULL && bi->bat != NULL ? bi->bat->name : "Medium", level);
231
return (level >= bi->min && level <= bi->max) ? MATCH : DONT_MATCH;
234
/* static int acpi_battery_update(void)
236
* reads temperature valuse ant compute a medium value
238
static int acpi_battery_update(void) {
243
int i=0, capacity=0, remaining=0, tmp_remaining=0, n_read=0;
245
/* Read battery informations */
246
for (i=0; i<bat_num; i++) {
248
/* avoid reading the info file if configured */
249
if (!configuration->acpi_workaround) {
250
check_battery(&infos[i]);
254
/* if battery not present skip to the next one */
255
if (!infos[i].present || infos[i].capacity <= 0) {
259
** /proc/acpi/battery/.../state
261
snprintf(file_name, 256, "%s%s", infos[i].path, ACPI_BATTERY_STATE_FILE);
262
fp = fopen(file_name, "r");
264
clog(LOG_ERR, "%s: %s\n", file_name, strerror(errno));
265
clog(LOG_INFO, "battery path %s disappeared? "
266
"send SIGHUP to re-read batteries\n",
271
while (fgets(line, 100, fp)) {
272
if (sscanf(line, ACPI_BATTERY_REM_CAPACITY_FMT, &tmp_remaining, ignore) == 2) {
273
remaining += tmp_remaining;
274
capacity += infos[i].capacity;
275
infos[i].level = 100 * (tmp_remaining / (double)infos[i].capacity);
277
clog(LOG_INFO, "battery life for %s is %d%%\n",
278
infos[i].name, infos[i].level);
282
} /* end infos loop */
284
/* calculates medium battery life between all batteries */
286
battery_level = 100 * (remaining / (double)capacity);
290
clog(LOG_INFO, "medium battery life %d%%\n", battery_level);
295
static struct cpufreqd_keyword kw[] = {
296
{ .word = "battery_interval", .parse = &acpi_battery_parse, .evaluate = &acpi_battery_evaluate },
297
{ .word = NULL, .parse = NULL, .evaluate = NULL, .free = NULL }
300
static struct cpufreqd_plugin acpi_battery = {
301
.plugin_name = "acpi_battery_plugin", /* plugin_name */
302
.keywords = kw, /* config_keywords */
303
.plugin_init = &acpi_battery_init, /* plugin_init */
304
.plugin_exit = &acpi_battery_exit, /* plugin_exit */
305
.plugin_update = &acpi_battery_update, /* plugin_update */
308
struct cpufreqd_plugin *create_plugin (void) {
309
return &acpi_battery;