2008-03-03 01:48:37 -08:00
|
|
|
/*
|
|
|
|
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
|
|
|
|
*/
|
|
|
|
#include "e.h"
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
# include <sys/types.h>
|
|
|
|
# include <sys/sysctl.h>
|
|
|
|
# include <fcntl.h>
|
|
|
|
# ifdef __i386__
|
|
|
|
# include <machine/apm_bios.h>
|
|
|
|
# endif
|
|
|
|
# include <stdio.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_CFBASE_H
|
|
|
|
# include <CFBase.h>
|
|
|
|
# include <CFNumber.h>
|
|
|
|
# include <CFArray.h>
|
|
|
|
# include <CFDictionary.h>
|
|
|
|
# include <CFRunLoop.h>
|
|
|
|
# include <ps/IOPSKeys.h>
|
|
|
|
# include <ps/IOPowerSources.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
/* supported batery system schemes - irrespective of OS */
|
|
|
|
#define CHECK_NONE 0
|
|
|
|
#define CHECK_ACPI 1
|
|
|
|
#define CHECK_APM 2
|
|
|
|
#define CHECK_PMU 3
|
|
|
|
#define CHECK_SYS_CLASS_POWER_SUPPLY 4
|
|
|
|
|
|
|
|
static void init(void);
|
|
|
|
static int poll_cb(void *data);
|
|
|
|
|
|
|
|
static int poll_interval = 512;
|
|
|
|
static Ecore_Poller *poller = NULL;
|
|
|
|
|
|
|
|
static int mode = CHECK_NONE;
|
|
|
|
|
|
|
|
static int time_left = -2;
|
|
|
|
static int battery_full = -2;
|
|
|
|
static int have_battery = -2;
|
|
|
|
static int have_power = -2;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* UTILS */
|
|
|
|
static int
|
|
|
|
int_file_get(const char *file)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
int val = -1;
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
f = fopen(file, "r");
|
|
|
|
if (f)
|
|
|
|
{
|
|
|
|
fgets(buf, sizeof(buf), f);
|
|
|
|
val = atoi(buf);
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
str_file_get(const char *file)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
char *val = NULL;
|
|
|
|
char buf[4096];
|
|
|
|
int len;
|
|
|
|
|
|
|
|
f = fopen(file, "r");
|
|
|
|
if (f)
|
|
|
|
{
|
|
|
|
fgets(buf, sizeof(buf), f);
|
|
|
|
buf[sizeof(buf) - 1] = 0;
|
|
|
|
len = strlen(buf);
|
|
|
|
if (len > 0) buf[len - 1] = 0;
|
|
|
|
val = strdup(buf);
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
int_get(char *buf)
|
|
|
|
{
|
|
|
|
char *p, *q;
|
|
|
|
|
|
|
|
p = strchr(buf, ':');
|
|
|
|
if (!p) return 0;
|
|
|
|
p++;
|
|
|
|
while (*p == ' ') p++;
|
|
|
|
q = p;
|
|
|
|
while ((*q != ' ') && (*q != '\n')) q++;
|
|
|
|
if (q) *q = 0;
|
|
|
|
return atoi(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
str_get(char *buf)
|
|
|
|
{
|
|
|
|
char *p, *q;
|
|
|
|
|
|
|
|
p = strchr(buf, ':');
|
|
|
|
if (!p) return NULL;
|
|
|
|
p++;
|
|
|
|
while (*p == ' ') p++;
|
|
|
|
q = p;
|
|
|
|
while ((*q) && (*q != ' ') && (*q != '\n')) q++;
|
|
|
|
if (q) *q = 0;
|
|
|
|
return strdup(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
axtoi(char *arg)
|
|
|
|
{
|
|
|
|
int n, val, pwr=1, m, rc = 0;
|
|
|
|
char hex[9], c;
|
|
|
|
|
|
|
|
for (n = 0, m = 0; n < strlen(arg); n++)
|
|
|
|
{
|
|
|
|
if (arg[n] != ' ')
|
|
|
|
{
|
|
|
|
hex[m++] = c = toupper(arg[n]);
|
|
|
|
if ((m == sizeof(hex)) || (c < '0') || (c > 'F'))
|
|
|
|
return 0; /* overflow or invalid */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hex[m] = 0; /* terminate string */
|
|
|
|
|
|
|
|
for (n = 0; n < m; n++)
|
|
|
|
{
|
|
|
|
c = hex[m-n-1];
|
|
|
|
if ((c >= 'A') && (c <= 'F'))
|
|
|
|
val = c -'A' + 10;
|
|
|
|
else
|
|
|
|
val = c - '0';
|
|
|
|
rc = rc + val * pwr;
|
|
|
|
pwr *= 16;
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
|
|
|
|
#define BATTERY_STATE_NONE 0
|
|
|
|
#define BATTERY_STATE_DISCHARGING 1
|
|
|
|
#define BATTERY_STATE_CHARGING 2
|
|
|
|
#define BATTERY_STATE_REMOVED 7
|
|
|
|
|
|
|
|
/***---***/
|
|
|
|
static void
|
|
|
|
bsd_acpi_init(void)
|
|
|
|
{
|
|
|
|
/* nothing to do */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bsd_acpi_check(void)
|
|
|
|
{
|
|
|
|
int bat_val = 0;
|
|
|
|
int mib_state[4];
|
|
|
|
int mib_life[4];
|
|
|
|
int mib_time[4];
|
|
|
|
int mib_units[4];
|
|
|
|
size_t len;
|
|
|
|
int state = 0;
|
|
|
|
int level = 0;
|
|
|
|
int time_min = 0;
|
|
|
|
int life = 0;
|
|
|
|
int batteries = 0;
|
|
|
|
|
|
|
|
time_left = -1;
|
|
|
|
battery_full = -1;
|
|
|
|
have_battery = 0;
|
|
|
|
have_power = 0;
|
|
|
|
|
|
|
|
/* Read some information on first run. */
|
|
|
|
len = 4;
|
|
|
|
sysctlnametomib("hw.acpi.battery.state", mib_state, &len);
|
|
|
|
len = sizeof(state);
|
|
|
|
if (sysctl(mib_state, 4, &state, &len, NULL, 0) == -1)
|
|
|
|
/* ERROR */
|
|
|
|
state = -1;
|
|
|
|
|
|
|
|
len = 4;
|
|
|
|
sysctlnametomib("hw.acpi.battery.life", mib_life, &len);
|
|
|
|
len = sizeof(life);
|
|
|
|
if (sysctl(mib_life, 4, &life, &len, NULL, 0) == -1)
|
|
|
|
/* ERROR */
|
|
|
|
level = -1;
|
|
|
|
bat_val = life;
|
|
|
|
|
|
|
|
len = 4;
|
|
|
|
sysctlnametomib("hw.acpi.battery.time", mib_time, &len);
|
|
|
|
len = sizeof(time);
|
|
|
|
if (sysctl(mib_time, 4, &time_min, &len, NULL, 0) == -1)
|
|
|
|
/* ERROR */
|
|
|
|
time_min = -1;
|
|
|
|
|
|
|
|
len = 4;
|
|
|
|
sysctlnametomib("hw.acpi.battery.units", mib_units, &len);
|
|
|
|
len = sizeof(batteries);
|
|
|
|
if (sysctl(mib_time, 4, &batteries, &len, NULL, 0) == -1)
|
|
|
|
/* ERROR */
|
|
|
|
batteries = 1;
|
|
|
|
|
|
|
|
if (time_min >= 0) time_left = time_min * 60;
|
|
|
|
|
|
|
|
if (batteries == 1) /* hw.acpi.battery.units = 1 means NO BATTS */
|
|
|
|
time_left = -1;
|
|
|
|
else if ((state == BATTERY_STATE_CHARGING) ||
|
|
|
|
(state == BATTERY_STATE_DISCHARGING))
|
|
|
|
{
|
|
|
|
have_battery = 1;
|
|
|
|
if (state == BATTERY_STATE_CHARGING) have_power = 1;
|
|
|
|
else if (state == BATTERY_STATE_DISCHARGING) have_power = 0;
|
|
|
|
if (level == -1) time_left = -1;
|
|
|
|
else if (time_min == -1)
|
|
|
|
{
|
|
|
|
time_left = -1;
|
|
|
|
battery_full = bat_val;
|
|
|
|
}
|
|
|
|
else battery_full = bat_val;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
have_battery = 1;
|
|
|
|
battery_full = 100;
|
|
|
|
time_left = -1;
|
|
|
|
have_power = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/***---***/
|
|
|
|
static void
|
|
|
|
bsd_apm_init(void)
|
|
|
|
{
|
|
|
|
/* nothing to do */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bsd_apm_check(void)
|
|
|
|
{
|
|
|
|
int ac_stat, bat_stat, bat_val, time_val;
|
|
|
|
char buf[4096];
|
|
|
|
int hours, minutes;
|
|
|
|
int apm_fd = -1;
|
|
|
|
struct apm_info info;
|
|
|
|
|
|
|
|
time_left = -1;
|
|
|
|
battery_full = -1;
|
|
|
|
have_battery = 0;
|
|
|
|
have_power = 0;
|
|
|
|
|
|
|
|
apm_fd = open("/dev/apm", O_RDONLY);
|
|
|
|
if ((apm_fd != -1) && (ioctl(apm_fd, APMIO_GETINFO, &info) != -1))
|
|
|
|
{
|
|
|
|
/* set values */
|
|
|
|
ac_stat = info.ai_acline;
|
|
|
|
bat_stat = info.ai_batt_stat;
|
|
|
|
bat_val = info.ai_batt_life;
|
|
|
|
time_val = info.ai_batt_time;
|
|
|
|
}
|
|
|
|
else return;
|
|
|
|
|
|
|
|
if (info.ai_batteries == 1) /* ai_batteries == 1 means NO battery,
|
|
|
|
* ai_batteries == 2 means 1 battery */
|
|
|
|
{
|
|
|
|
have_power = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ac_stat) /* Wallpowered */
|
|
|
|
{
|
|
|
|
have_power= 1;
|
|
|
|
have_battery = 1;
|
|
|
|
switch (bat_stat) /* On FreeBSD the time_val is -1 when AC ist plugged
|
|
|
|
* in. This means we don't know how long the battery
|
|
|
|
* will recharge */
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
battery_full = 100;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
battery_full = 50;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
battery_full = 25;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
battery_full = 100;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else /* Running on battery */
|
|
|
|
{
|
|
|
|
have_battery = 1;
|
|
|
|
battery_full = bat_val;
|
|
|
|
time_left = time_val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(HAVE_CFBASE_H) /* OS X */
|
|
|
|
/***---***/
|
|
|
|
static void darwin_init(void);
|
|
|
|
static void darwin_check(void);
|
|
|
|
|
|
|
|
static void
|
|
|
|
darwin_init(void)
|
|
|
|
{
|
|
|
|
/* nothing to do */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
darwin_check(void)
|
|
|
|
{
|
|
|
|
const void *values;
|
|
|
|
int device_num, device_count;
|
|
|
|
int currentval = 0, maxval = 0;
|
|
|
|
char buf[4096];
|
|
|
|
CFTypeRef blob;
|
|
|
|
CFArrayRef sources;
|
|
|
|
CFDictionaryRef device_dict;
|
|
|
|
|
|
|
|
time_left = -1;
|
|
|
|
battery_full = -1;
|
|
|
|
have_battery = 0;
|
|
|
|
have_power = 0;
|
|
|
|
|
|
|
|
/* Retrieve the power source data and the array of sources. */
|
|
|
|
blob = IOPSCopyPowerSourcesInfo();
|
|
|
|
sources = IOPSCopyPowerSourcesList(blob);
|
|
|
|
device_count = CFArrayGetCount(sources);
|
|
|
|
for (device_num = 0; device_num < device_count; device_num++)
|
|
|
|
{
|
|
|
|
CFTypeRef ps;
|
|
|
|
|
|
|
|
/* Retrieve a dictionary of values for this device and the count of keys in the dictionary. */
|
|
|
|
ps = CFArrayGetValueAtIndex(sources, device_num);
|
|
|
|
device_dict = IOPSGetPowerSourceDescription(blob, ps);
|
|
|
|
/* Retrieve the charging key and save the present charging value if one exists. */
|
|
|
|
if (CFDictionaryGetValueIfPresent(device_dict,
|
|
|
|
CFSTR(kIOPSIsChargingKey), &values))
|
|
|
|
{
|
|
|
|
have_battery = 1;
|
|
|
|
if (CFBooleanGetValue(values) > 0) have_power = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!have_battery)
|
|
|
|
{
|
|
|
|
CFRelease(sources);
|
|
|
|
CFRelease(blob);
|
|
|
|
have_power = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Retrieve the current capacity key. */
|
|
|
|
values = CFDictionaryGetValue(device_dict, CFSTR(kIOPSCurrentCapacityKey));
|
|
|
|
CFNumberGetValue(values, kCFNumberSInt32Type, ¤tval);
|
|
|
|
/* Retrieve the max capacity key. */
|
|
|
|
values = CFDictionaryGetValue(device_dict, CFSTR(kIOPSMaxCapacityKey));
|
|
|
|
CFNumberGetValue(values, kCFNumberSInt32Type, &maxval);
|
|
|
|
/* Calculate the percentage charged. */
|
|
|
|
battery_full = (currentval * 100) / maxval;
|
|
|
|
|
|
|
|
/* Retrieve the remaining battery power or time until charged in minutes. */
|
|
|
|
if (!have_power)
|
|
|
|
{
|
|
|
|
values = CFDictionaryGetValue(device_dict, CFSTR(kIOPSTimeToEmptyKey));
|
|
|
|
CFNumberGetValue(values, kCFNumberSInt32Type, ¤tval);
|
|
|
|
time_left = currentval * 60;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
values = CFDictionaryGetValue(device_dict, CFSTR(kIOPSTimeToFullChargeKey));
|
|
|
|
CFNumberGetValue(values, kCFNumberSInt32Type, ¤tval);
|
|
|
|
time_left = currentval * 60;
|
|
|
|
}
|
|
|
|
CFRelease(sources);
|
|
|
|
CFRelease(blob);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***---***/
|
|
|
|
/* new linux power class api to get power info - brand new and this code
|
|
|
|
* may have bugs, but it is a good attempt to get it right */
|
|
|
|
static int linux_sys_class_power_supply_cb_event_fd_active(void *data, Ecore_Fd_Handler *fd_handler);
|
|
|
|
static void linux_sys_class_power_supply_init(void);
|
|
|
|
static void linux_sys_class_power_supply_check(void);
|
|
|
|
typedef struct _Sys_Class_Power_Supply_Uevent Sys_Class_Power_Supply_Uevent;
|
|
|
|
|
2008-03-03 06:35:26 -08:00
|
|
|
#define BASIS_CHARGE 1
|
|
|
|
#define BASIS_ENERGY 2
|
|
|
|
#define BASIS_VOLTAGE 3
|
|
|
|
|
2008-03-03 01:48:37 -08:00
|
|
|
struct _Sys_Class_Power_Supply_Uevent
|
|
|
|
{
|
2008-03-03 06:35:26 -08:00
|
|
|
char *name;
|
2008-03-03 01:48:37 -08:00
|
|
|
int fd;
|
|
|
|
Ecore_Fd_Handler *fd_handler;
|
2008-03-03 06:35:26 -08:00
|
|
|
|
|
|
|
int present;
|
|
|
|
|
|
|
|
int basis;
|
|
|
|
int basis_empty;
|
|
|
|
int basis_full;
|
|
|
|
|
|
|
|
unsigned char have_current_avg : 1;
|
|
|
|
unsigned char have_current_now : 1;
|
2008-03-03 01:48:37 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
static Ecore_List *events = NULL;
|
|
|
|
static Ecore_Timer *sys_class_delay_check = NULL;
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_sys_class_powe_supply_cb_delay_check(void *data)
|
|
|
|
{
|
|
|
|
linux_sys_class_power_supply_init();
|
|
|
|
poll_cb(NULL);
|
|
|
|
sys_class_delay_check = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_sys_class_power_supply_cb_event_fd_active(void *data, Ecore_Fd_Handler *fd_handler)
|
|
|
|
{
|
|
|
|
Sys_Class_Power_Supply_Uevent *sysev;
|
|
|
|
|
|
|
|
sysev = data;
|
|
|
|
if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
|
|
|
|
{
|
|
|
|
int lost = 0;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
char buf[1024];
|
|
|
|
int num;
|
|
|
|
|
|
|
|
if ((num = read(sysev->fd, buf, sizeof(buf))) < 1)
|
|
|
|
{
|
|
|
|
lost = ((errno == EIO) ||
|
|
|
|
(errno == EBADF) ||
|
|
|
|
(errno == EPIPE) ||
|
|
|
|
(errno == EINVAL) ||
|
2008-03-03 03:36:59 -08:00
|
|
|
(errno == ENOSPC));
|
|
|
|
if (num == 0) break;
|
2008-03-03 01:48:37 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (lost)
|
|
|
|
{
|
|
|
|
ecore_list_goto(events, sysev);
|
|
|
|
ecore_list_remove(events);
|
2008-03-03 06:35:26 -08:00
|
|
|
|
|
|
|
if (sysev->fd_handler)
|
|
|
|
ecore_main_fd_handler_del(sysev->fd_handler);
|
|
|
|
if (sysev->fd >= 0) close(sysev->fd);
|
|
|
|
free(sysev->name);
|
2008-03-03 01:48:37 -08:00
|
|
|
free(sysev);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (sys_class_delay_check) ecore_timer_del(sys_class_delay_check);
|
|
|
|
sys_class_delay_check = ecore_timer_add(0.2, linux_sys_class_powe_supply_cb_delay_check, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-03-03 06:35:26 -08:00
|
|
|
linux_sys_class_power_supply_sysev_init(Sys_Class_Power_Supply_Uevent *sysev)
|
2008-03-03 01:48:37 -08:00
|
|
|
{
|
|
|
|
char buf[4096];
|
2008-03-03 06:35:26 -08:00
|
|
|
|
|
|
|
sysev->basis = 0;
|
|
|
|
sysev->have_current_avg = 0;
|
|
|
|
sysev->have_current_now = 0;
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/present", sysev->name);
|
|
|
|
sysev->present = int_file_get(buf);
|
|
|
|
if (!sysev->present) return;
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/current_avg", sysev->name);
|
|
|
|
if (ecore_file_exists(buf)) sysev->have_current_avg = 1;
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/current_now", sysev->name);
|
|
|
|
if (ecore_file_exists(buf)) sysev->have_current_now = 1;
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/voltage_full", sysev->name);
|
|
|
|
if (ecore_file_exists(buf)) sysev->basis = BASIS_VOLTAGE;
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/voltage_full_design", sysev->name);
|
|
|
|
if (ecore_file_exists(buf)) sysev->basis = BASIS_VOLTAGE;
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/energy_full", sysev->name);
|
|
|
|
if (ecore_file_exists(buf)) sysev->basis = BASIS_ENERGY;
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/energy_full_design", sysev->name);
|
|
|
|
if (ecore_file_exists(buf)) sysev->basis = BASIS_ENERGY;
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/charge_full", sysev->name);
|
|
|
|
if (ecore_file_exists(buf)) sysev->basis = BASIS_CHARGE;
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/charge_full_design", sysev->name);
|
|
|
|
if (ecore_file_exists(buf)) sysev->basis = BASIS_CHARGE;
|
|
|
|
|
|
|
|
if (sysev->basis == BASIS_CHARGE)
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/charge_full", sysev->name);
|
|
|
|
sysev->basis_full = int_file_get(buf);
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/charge_empty", sysev->name);
|
|
|
|
sysev->basis_empty = int_file_get(buf);
|
|
|
|
if (sysev->basis_full < 0)
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/charge_full_design", sysev->name);
|
|
|
|
sysev->basis_full = int_file_get(buf);
|
|
|
|
}
|
|
|
|
if (sysev->basis_empty < 0)
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/charge_empty_design", sysev->name);
|
|
|
|
sysev->basis_empty = int_file_get(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (sysev->basis == BASIS_ENERGY)
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/energy_full", sysev->name);
|
|
|
|
sysev->basis_full = int_file_get(buf);
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/energy_empty", sysev->name);
|
|
|
|
sysev->basis_empty = int_file_get(buf);
|
|
|
|
if (sysev->basis_full < 0)
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/energy_full_design", sysev->name);
|
|
|
|
sysev->basis_full = int_file_get(buf);
|
|
|
|
}
|
|
|
|
if (sysev->basis_empty < 0)
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/energy_empty_design", sysev->name);
|
|
|
|
sysev->basis_empty = int_file_get(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (sysev->basis == BASIS_VOLTAGE)
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/voltage_full", sysev->name);
|
|
|
|
sysev->basis_full = int_file_get(buf);
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/voltage_empty", sysev->name);
|
|
|
|
sysev->basis_empty = int_file_get(buf);
|
|
|
|
if (sysev->basis_full < 0)
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/voltage_full_design", sysev->name);
|
|
|
|
sysev->basis_full = int_file_get(buf);
|
|
|
|
}
|
|
|
|
if (sysev->basis_empty < 0)
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/voltage_empty_design", sysev->name);
|
|
|
|
sysev->basis_empty = int_file_get(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-03-03 01:48:37 -08:00
|
|
|
|
2008-03-03 06:35:26 -08:00
|
|
|
static void
|
|
|
|
linux_sys_class_power_supply_init(void)
|
|
|
|
{
|
2008-03-03 01:48:37 -08:00
|
|
|
if (events)
|
|
|
|
{
|
2008-03-03 06:35:26 -08:00
|
|
|
Sys_Class_Power_Supply_Uevent *sysev;
|
2008-03-03 01:48:37 -08:00
|
|
|
|
2008-03-03 06:35:26 -08:00
|
|
|
ecore_list_first_goto(events);
|
|
|
|
while ((sysev = ecore_list_next(events)))
|
|
|
|
linux_sys_class_power_supply_sysev_init(sysev);
|
2008-03-03 01:48:37 -08:00
|
|
|
}
|
2008-03-03 06:35:26 -08:00
|
|
|
else
|
2008-03-03 01:48:37 -08:00
|
|
|
{
|
2008-03-03 06:35:26 -08:00
|
|
|
Ecore_List *bats;
|
|
|
|
char *name;
|
|
|
|
char buf[4096];
|
|
|
|
|
|
|
|
bats = ecore_file_ls("/sys/class/power_supply/");
|
|
|
|
if (bats)
|
2008-03-03 01:48:37 -08:00
|
|
|
{
|
2008-03-03 06:35:26 -08:00
|
|
|
events = ecore_list_new();
|
|
|
|
while ((name = ecore_list_next(bats)))
|
2008-03-03 01:48:37 -08:00
|
|
|
{
|
|
|
|
Sys_Class_Power_Supply_Uevent *sysev;
|
2008-03-03 06:35:26 -08:00
|
|
|
|
|
|
|
if (strncasecmp("bat", name, 3)) continue;
|
2008-03-03 01:48:37 -08:00
|
|
|
sysev = E_NEW(Sys_Class_Power_Supply_Uevent, 1);
|
2008-03-03 06:35:26 -08:00
|
|
|
sysev->name = strdup(name);
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/uevent", name);
|
|
|
|
sysev->fd = open(buf, O_RDONLY);
|
|
|
|
if (sysev->fd >= 0)
|
|
|
|
sysev->fd_handler = ecore_main_fd_handler_add(sysev->fd,
|
|
|
|
ECORE_FD_READ,
|
|
|
|
linux_sys_class_power_supply_cb_event_fd_active,
|
|
|
|
sysev,
|
|
|
|
NULL, NULL);
|
2008-03-03 01:48:37 -08:00
|
|
|
ecore_list_append(events, sysev);
|
2008-03-03 06:35:26 -08:00
|
|
|
linux_sys_class_power_supply_sysev_init(sysev);
|
2008-03-03 01:48:37 -08:00
|
|
|
}
|
2008-03-03 06:35:26 -08:00
|
|
|
ecore_list_destroy(bats);
|
2008-03-03 01:48:37 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
linux_sys_class_power_supply_check(void)
|
|
|
|
{
|
|
|
|
char *name;
|
|
|
|
char buf[4096];
|
|
|
|
|
|
|
|
battery_full = -1;
|
|
|
|
time_left = -1;
|
|
|
|
have_battery = 0;
|
|
|
|
have_power = 0;
|
2008-03-03 06:35:26 -08:00
|
|
|
|
|
|
|
if (events)
|
2008-03-03 01:48:37 -08:00
|
|
|
{
|
2008-03-03 06:35:26 -08:00
|
|
|
Sys_Class_Power_Supply_Uevent *sysev;
|
|
|
|
int total_pwr_now;
|
|
|
|
int total_pwr_max;
|
2008-03-03 01:48:37 -08:00
|
|
|
|
2008-03-03 06:35:26 -08:00
|
|
|
total_pwr_now = 0;
|
|
|
|
total_pwr_max = 0;
|
2008-03-03 01:48:37 -08:00
|
|
|
time_left = 0;
|
2008-03-03 06:35:26 -08:00
|
|
|
ecore_list_first_goto(events);
|
|
|
|
while ((sysev = ecore_list_next(events)))
|
2008-03-03 01:48:37 -08:00
|
|
|
{
|
|
|
|
char *tmp;
|
|
|
|
int present = 0;
|
|
|
|
int charging = -1;
|
|
|
|
int capacity = -1;
|
2008-03-03 06:35:26 -08:00
|
|
|
int current = -1;
|
2008-03-03 01:48:37 -08:00
|
|
|
int time_to_full = -1;
|
|
|
|
int time_to_empty = -1;
|
|
|
|
int full = -1;
|
|
|
|
int pwr_now = -1;
|
|
|
|
int pwr_empty = -1;
|
|
|
|
int pwr_full = -1;
|
2008-03-03 06:35:26 -08:00
|
|
|
int pwr = 0;
|
2008-03-03 01:48:37 -08:00
|
|
|
|
2008-03-03 06:35:26 -08:00
|
|
|
name = sysev->name;
|
2008-03-03 01:48:37 -08:00
|
|
|
|
|
|
|
/* fetch more generic info */
|
2008-03-03 06:35:26 -08:00
|
|
|
// init
|
|
|
|
present = sysev->present;
|
|
|
|
if (!present) continue;
|
|
|
|
|
2008-03-03 01:48:37 -08:00
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/capacity", name);
|
|
|
|
capacity = int_file_get(buf);
|
2008-03-03 06:35:26 -08:00
|
|
|
if (sysev->have_current_avg)
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/current_avg", name);
|
|
|
|
current = int_file_get(buf);
|
|
|
|
}
|
|
|
|
else if (sysev->have_current_now)
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/current_now", name);
|
|
|
|
current = int_file_get(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FIXME: do we get a uevent on going from charging to full?
|
|
|
|
* if so, move this to init */
|
2008-03-03 01:48:37 -08:00
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/status", name);
|
|
|
|
tmp = str_file_get(buf);
|
|
|
|
if (tmp)
|
|
|
|
{
|
2008-03-03 06:35:26 -08:00
|
|
|
full = 0;
|
2008-03-03 01:48:37 -08:00
|
|
|
if (!strncasecmp("discharging", tmp, 11)) charging = 0;
|
|
|
|
else if (!strncasecmp("charging", tmp, 8)) charging = 1;
|
|
|
|
else if (!strncasecmp("full", tmp, 4))
|
|
|
|
{
|
|
|
|
full = 1;
|
|
|
|
charging = 0;
|
|
|
|
}
|
|
|
|
free(tmp);
|
|
|
|
}
|
2008-03-03 06:35:26 -08:00
|
|
|
/* some batteries can/will/want to predict how long they will
|
2008-03-03 01:48:37 -08:00
|
|
|
* last. if so - take what the battery says. too bad if it's
|
|
|
|
* wrong. that's a buggy battery or driver */
|
2008-03-03 06:35:26 -08:00
|
|
|
if (!full)
|
|
|
|
{
|
|
|
|
if (charging)
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/time_to_full_now", name);
|
|
|
|
time_to_full = int_file_get(buf);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/time_to_empty_now", name);
|
|
|
|
time_to_empty = int_file_get(buf);
|
|
|
|
}
|
|
|
|
}
|
2008-03-03 01:48:37 -08:00
|
|
|
|
|
|
|
/* now get charge, energy and voltage. take the one that provides
|
|
|
|
* the best info (charge first, then energy, then voltage */
|
2008-03-03 06:35:26 -08:00
|
|
|
if (sysev->basis == BASIS_CHARGE)
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/charge_now", name);
|
|
|
|
else if (sysev->basis == BASIS_ENERGY)
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/energy_now", name);
|
|
|
|
else if (sysev->basis == BASIS_VOLTAGE)
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/power_supply/%s/voltage_now", name);
|
|
|
|
pwr_now = int_file_get(buf);
|
|
|
|
pwr_empty = sysev->basis_empty;
|
|
|
|
pwr_full = sysev->basis_full;
|
2008-03-03 01:48:37 -08:00
|
|
|
|
|
|
|
if (pwr_empty < 0) pwr_empty = 0;
|
2008-03-03 06:35:26 -08:00
|
|
|
|
|
|
|
if (full) pwr_now = pwr_full;
|
2008-03-03 01:48:37 -08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (pwr_now < 0)
|
2008-03-03 19:35:03 -08:00
|
|
|
pwr_now = (((long long)capacity * ((long long)pwr_full - (long long)pwr_empty)) / 100) + pwr_empty;
|
2008-03-03 01:48:37 -08:00
|
|
|
}
|
|
|
|
|
2008-03-03 06:35:26 -08:00
|
|
|
if (sysev->present) have_battery = 1;
|
2008-03-03 01:48:37 -08:00
|
|
|
if (charging)
|
|
|
|
{
|
2008-03-03 06:35:26 -08:00
|
|
|
pwr_now = pwr_now;
|
2008-03-03 01:48:37 -08:00
|
|
|
have_power = 1;
|
|
|
|
if (time_to_full >= 0)
|
|
|
|
{
|
|
|
|
if (time_to_full > time_left)
|
|
|
|
time_left = time_to_full;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-03-03 06:35:26 -08:00
|
|
|
if (current == 0) time_left = 0;
|
|
|
|
else if (current < 0) time_left = -1;
|
2008-03-03 01:48:37 -08:00
|
|
|
else
|
|
|
|
{
|
2008-03-03 19:35:03 -08:00
|
|
|
pwr = (((long long)pwr_full - (long long)pwr_now) * 3600) / -current;
|
2008-03-03 06:35:26 -08:00
|
|
|
if (pwr > time_left) time_left = pwr;
|
2008-03-03 01:48:37 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-03-03 06:35:26 -08:00
|
|
|
have_power = 0;
|
|
|
|
if (time_to_empty >= 0) time_left += time_to_empty;
|
2008-03-03 01:48:37 -08:00
|
|
|
else
|
|
|
|
{
|
2008-03-03 06:35:26 -08:00
|
|
|
if (time_to_empty < 0)
|
2008-03-03 01:48:37 -08:00
|
|
|
{
|
2008-03-03 06:35:26 -08:00
|
|
|
if (current > 0)
|
2008-03-03 01:48:37 -08:00
|
|
|
{
|
2008-03-03 19:35:03 -08:00
|
|
|
pwr = (((long long)pwr_now - (long long)pwr_empty) * 3600) / current;
|
2008-03-03 01:48:37 -08:00
|
|
|
time_left += pwr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
total_pwr_now += pwr_now - pwr_empty;
|
|
|
|
total_pwr_max += pwr_full - pwr_empty;
|
|
|
|
}
|
|
|
|
if (total_pwr_max > 0)
|
2008-03-03 17:06:58 -08:00
|
|
|
battery_full = ((long long)total_pwr_now * 100) / total_pwr_max;
|
2008-03-03 01:48:37 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***---***/
|
|
|
|
/* "here and now" ACPI based power checking. is there for linux and most
|
|
|
|
* modern laptops. as of linux 2.6.24 it is replaced with
|
|
|
|
* linux_sys_class_power_supply_init/check() though as this is the new
|
|
|
|
* power class api to poll for power stuff
|
|
|
|
*/
|
|
|
|
static int linux_acpi_cb_acpid_add(void *data, int type, void *event);
|
|
|
|
static int linux_acpi_cb_acpid_del(void *data, int type, void *event);
|
|
|
|
static int linux_acpi_cb_acpid_data(void *data, int type, void *event);
|
|
|
|
static void linux_acpi_init(void);
|
|
|
|
static void linux_acpi_check(void);
|
|
|
|
|
|
|
|
static int acpi_max_full = -1;
|
|
|
|
static int acpi_max_design = -1;
|
|
|
|
static Ecore_Con_Server *acpid = NULL;
|
|
|
|
static Ecore_Event_Handler *acpid_handler_add = NULL;
|
|
|
|
static Ecore_Event_Handler *acpid_handler_del = NULL;
|
|
|
|
static Ecore_Event_Handler *acpid_handler_data = NULL;
|
|
|
|
static Ecore_Timer *delay_check = NULL;
|
|
|
|
static int event_fd = -1;
|
|
|
|
static Ecore_Fd_Handler *event_fd_handler = NULL;
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_acpi_cb_delay_check(void *data)
|
|
|
|
{
|
|
|
|
linux_acpi_init();
|
|
|
|
poll_cb(NULL);
|
|
|
|
delay_check = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_acpi_cb_acpid_add(void *data, int type, void *event)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_acpi_cb_acpid_del(void *data, int type, void *event)
|
|
|
|
{
|
|
|
|
ecore_con_server_del(acpid);
|
|
|
|
acpid = NULL;
|
|
|
|
if (acpid_handler_add) ecore_event_handler_del(acpid_handler_add);
|
|
|
|
acpid_handler_add = NULL;
|
|
|
|
if (acpid_handler_del) ecore_event_handler_del(acpid_handler_del);
|
|
|
|
acpid_handler_del = NULL;
|
|
|
|
if (acpid_handler_data) ecore_event_handler_del(acpid_handler_data);
|
|
|
|
acpid_handler_data = NULL;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_acpi_cb_acpid_data(void *data, int type, void *event)
|
|
|
|
{
|
|
|
|
Ecore_Con_Event_Server_Data *ev;
|
|
|
|
|
|
|
|
ev = event;
|
|
|
|
if (delay_check) ecore_timer_del(delay_check);
|
|
|
|
delay_check = ecore_timer_add(0.2, linux_acpi_cb_delay_check, NULL);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_acpi_cb_event_fd_active(void *data, Ecore_Fd_Handler *fd_handler)
|
|
|
|
{
|
|
|
|
if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
|
|
|
|
{
|
|
|
|
int lost = 0;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
char buf[1024];
|
|
|
|
int num;
|
|
|
|
|
|
|
|
if ((num = read(event_fd, buf, sizeof(buf))) < 1)
|
|
|
|
{
|
|
|
|
lost = ((errno == EIO) ||
|
|
|
|
(errno == EBADF) ||
|
|
|
|
(errno == EPIPE) ||
|
|
|
|
(errno == EINVAL) ||
|
2008-03-03 03:36:59 -08:00
|
|
|
(errno == ENOSPC));
|
|
|
|
if (num == 0) break;
|
2008-03-03 01:48:37 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (lost)
|
|
|
|
{
|
|
|
|
ecore_main_fd_handler_del(event_fd_handler);
|
|
|
|
event_fd_handler = NULL;
|
|
|
|
close(event_fd);
|
|
|
|
event_fd = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (delay_check) ecore_timer_del(delay_check);
|
|
|
|
delay_check = ecore_timer_add(0.2, linux_acpi_cb_delay_check, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
linux_acpi_init(void)
|
|
|
|
{
|
|
|
|
Ecore_List *powers;
|
|
|
|
Ecore_List *bats;
|
|
|
|
|
|
|
|
bats = ecore_file_ls("/proc/acpi/battery");
|
|
|
|
if (bats)
|
|
|
|
{
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
have_power = 0;
|
|
|
|
powers = ecore_file_ls("/proc/acpi/ac_adapter");
|
|
|
|
if (powers)
|
|
|
|
{
|
|
|
|
char *name;
|
|
|
|
while ((name = ecore_list_next(powers)))
|
|
|
|
{
|
|
|
|
char buf[4096];
|
|
|
|
FILE *f;
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "/proc/acpi/ac_adapter/%s/state", name);
|
|
|
|
f = fopen(buf, "r");
|
|
|
|
if (f)
|
|
|
|
{
|
|
|
|
char *tmp;
|
|
|
|
|
|
|
|
/* state */
|
|
|
|
fgets(buf, sizeof(buf), f); buf[sizeof(buf) - 1] = 0;
|
|
|
|
tmp = str_get(buf);
|
|
|
|
if (tmp)
|
|
|
|
{
|
|
|
|
if (!strcmp(tmp, "on-line")) have_power = 1;
|
|
|
|
free(tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ecore_list_destroy(powers);
|
|
|
|
}
|
|
|
|
|
|
|
|
have_battery = 0;
|
|
|
|
acpi_max_full = 0;
|
|
|
|
acpi_max_design = 0;
|
|
|
|
while ((name = ecore_list_next(bats)))
|
|
|
|
{
|
|
|
|
char buf[4096];
|
|
|
|
FILE *f;
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "/proc/acpi/battery/%s/info", name);
|
|
|
|
f = fopen(buf, "r");
|
|
|
|
if (f)
|
|
|
|
{
|
|
|
|
char *tmp;
|
|
|
|
|
|
|
|
/* present */
|
|
|
|
fgets(buf, sizeof(buf), f); buf[sizeof(buf) - 1] = 0;
|
|
|
|
tmp = str_get(buf);
|
|
|
|
if (tmp)
|
|
|
|
{
|
|
|
|
if (!strcmp(tmp, "yes")) have_battery = 1;
|
|
|
|
free(tmp);
|
|
|
|
}
|
|
|
|
/* design cap */
|
|
|
|
fgets(buf, sizeof(buf), f); buf[sizeof(buf) - 1] = 0;
|
|
|
|
tmp = str_get(buf);
|
|
|
|
if (tmp)
|
|
|
|
{
|
|
|
|
if (strcmp(tmp, "unknown")) acpi_max_design += atoi(tmp);
|
|
|
|
free(tmp);
|
|
|
|
}
|
|
|
|
/* last full cap */
|
|
|
|
fgets(buf, sizeof(buf), f); buf[sizeof(buf) - 1] = 0;
|
|
|
|
tmp = str_get(buf);
|
|
|
|
if (tmp)
|
|
|
|
{
|
|
|
|
if (strcmp(tmp, "unknown")) acpi_max_full += atoi(tmp);
|
|
|
|
free(tmp);
|
|
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ecore_list_destroy(bats);
|
|
|
|
}
|
|
|
|
if (!acpid)
|
|
|
|
{
|
|
|
|
acpid = ecore_con_server_connect(ECORE_CON_LOCAL_SYSTEM,
|
|
|
|
"/var/run/acpid.socket", -1, NULL);
|
|
|
|
if (acpid)
|
|
|
|
{
|
|
|
|
acpid_handler_add = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD,
|
|
|
|
linux_acpi_cb_acpid_add, NULL);
|
|
|
|
acpid_handler_del = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL,
|
|
|
|
linux_acpi_cb_acpid_del, NULL);
|
|
|
|
acpid_handler_data = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA,
|
|
|
|
linux_acpi_cb_acpid_data, NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (event_fd < 0)
|
|
|
|
{
|
|
|
|
event_fd = open("/proc/acpi/event", O_RDONLY);
|
|
|
|
if (event_fd >= 0)
|
|
|
|
event_fd_handler = ecore_main_fd_handler_add(event_fd,
|
|
|
|
ECORE_FD_READ,
|
|
|
|
linux_acpi_cb_event_fd_active,
|
|
|
|
NULL,
|
|
|
|
NULL, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
linux_acpi_check(void)
|
|
|
|
{
|
|
|
|
Ecore_List *bats;
|
|
|
|
|
|
|
|
battery_full = -1;
|
|
|
|
time_left = -1;
|
|
|
|
have_battery = 0;
|
|
|
|
have_power = 0;
|
|
|
|
|
|
|
|
bats = ecore_file_ls("/proc/acpi/battery");
|
|
|
|
if (bats)
|
|
|
|
{
|
|
|
|
char *name;
|
|
|
|
int rate = 0;
|
|
|
|
int capacity = 0;
|
|
|
|
|
|
|
|
while ((name = ecore_list_next(bats)))
|
|
|
|
{
|
|
|
|
char buf[4096];
|
|
|
|
FILE *f;
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "/proc/acpi/battery/%s/state", name);
|
|
|
|
f = fopen(buf, "r");
|
|
|
|
if (f)
|
|
|
|
{
|
|
|
|
char *tmp;
|
|
|
|
|
|
|
|
/* present */
|
|
|
|
fgets(buf, sizeof(buf), f); buf[sizeof(buf) - 1] = 0;
|
|
|
|
tmp = str_get(buf);
|
|
|
|
if (tmp)
|
|
|
|
{
|
|
|
|
if (!strcmp(tmp, "yes")) have_battery = 1;
|
|
|
|
free(tmp);
|
|
|
|
}
|
|
|
|
/* capacity state: ok/? */
|
|
|
|
fgets(buf, sizeof(buf), f);
|
|
|
|
/* charging state: charging/? */
|
|
|
|
fgets(buf, sizeof(buf), f); buf[sizeof(buf) - 1] = 0;
|
|
|
|
tmp = str_get(buf);
|
|
|
|
if (tmp)
|
|
|
|
{
|
|
|
|
if (have_power == 0)
|
|
|
|
{
|
|
|
|
if (!strcmp(tmp, "charging")) have_power = 1;
|
|
|
|
}
|
|
|
|
free(tmp);
|
|
|
|
}
|
|
|
|
/* present rate: unknown/NNN */
|
|
|
|
fgets(buf, sizeof(buf), f); buf[sizeof(buf) - 1] = 0;
|
|
|
|
tmp = str_get(buf);
|
|
|
|
if (tmp)
|
|
|
|
{
|
|
|
|
if (strcmp(tmp, "unknown")) rate += atoi(tmp);
|
|
|
|
free(tmp);
|
|
|
|
}
|
|
|
|
/* remaining capacity: NNN */
|
|
|
|
fgets(buf, sizeof(buf), f); buf[sizeof(buf) - 1] = 0;
|
|
|
|
tmp = str_get(buf);
|
|
|
|
if (tmp)
|
|
|
|
{
|
|
|
|
if (strcmp(tmp, "unknown")) capacity += atoi(tmp);
|
|
|
|
free(tmp);
|
|
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ecore_list_destroy(bats);
|
|
|
|
if (acpi_max_full > 0)
|
2008-03-03 19:35:03 -08:00
|
|
|
battery_full = 100 * (long long)capacity / acpi_max_full;
|
2008-03-03 01:48:37 -08:00
|
|
|
else if (acpi_max_design > 0)
|
2008-03-03 19:35:03 -08:00
|
|
|
battery_full = 100 * (long long)capacity / acpi_max_design;
|
2008-03-03 01:48:37 -08:00
|
|
|
else
|
|
|
|
battery_full = -1;
|
|
|
|
if (rate <= 0) time_left = -1;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (have_power)
|
2008-03-03 19:35:03 -08:00
|
|
|
time_left = (3600 * ((long long)acpi_max_full - (long long)capacity)) / rate;
|
2008-03-03 01:48:37 -08:00
|
|
|
else
|
2008-03-03 19:35:03 -08:00
|
|
|
time_left = (3600 * (long long)capacity) / rate;
|
2008-03-03 01:48:37 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***---***/
|
|
|
|
/* old school apm support - very old laptops and some devices support this.
|
|
|
|
* this is here for legacy support and i wouldn't suggest spending any
|
|
|
|
* effort on it as it is complete below as best i know, but could have missed
|
|
|
|
* one or 2 things, but not worth fixing */
|
|
|
|
static void linux_apm_init(void);
|
|
|
|
static void linux_apm_check(void);
|
|
|
|
|
|
|
|
static void
|
|
|
|
linux_apm_init(void)
|
|
|
|
{
|
|
|
|
/* nothing to do */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
linux_apm_check(void)
|
|
|
|
{
|
|
|
|
FILE *f;
|
2008-03-13 12:13:36 -07:00
|
|
|
char s[256], s1[32], s2[32], s3[32];
|
2008-03-03 01:48:37 -08:00
|
|
|
int apm_flags, ac_stat, bat_stat, bat_flags, bat_val, time_val;
|
|
|
|
|
|
|
|
battery_full = -1;
|
|
|
|
time_left = -1;
|
|
|
|
have_battery = 0;
|
|
|
|
have_power = 0;
|
|
|
|
|
|
|
|
f = fopen("/proc/apm", "r");
|
|
|
|
if (!f) return;
|
|
|
|
|
|
|
|
fgets(s, sizeof(s), f); s[sizeof(s) - 1] = 0;
|
|
|
|
if (sscanf(s, "%*s %*s %x %x %x %x %s %s %s",
|
|
|
|
&apm_flags, &ac_stat, &bat_stat, &bat_flags, s1, s2, s3) != 7)
|
|
|
|
{
|
|
|
|
fclose(f);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
s1[strlen(s1) - 1] = 0;
|
|
|
|
bat_val = atoi(s1);
|
|
|
|
if (!strcmp(s3, "sec")) time_val = atoi(s2);
|
|
|
|
else if (!strcmp(s3, "min")) time_val = atoi(s2) * 60;
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
if ((bat_flags != 0xff) && (bat_flags & 0x80))
|
|
|
|
{
|
|
|
|
have_battery = 0;
|
|
|
|
have_power = 0;
|
|
|
|
battery_full = 100;
|
|
|
|
time_left = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bat_val >= 0)
|
|
|
|
{
|
|
|
|
have_battery = 1;
|
|
|
|
have_power = ac_stat;
|
|
|
|
battery_full = bat_val;
|
|
|
|
if (battery_full > 100) battery_full = 100;
|
|
|
|
if (ac_stat == 1) time_left = -1;
|
|
|
|
else time_left = time_val;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (bat_stat)
|
|
|
|
{
|
|
|
|
case 0: /* high */
|
|
|
|
have_battery = 1;
|
|
|
|
have_power = ac_stat;
|
|
|
|
battery_full = 100;
|
|
|
|
time_left = -1;
|
|
|
|
break;
|
|
|
|
case 1: /* medium */
|
|
|
|
have_battery = 1;
|
|
|
|
have_power = ac_stat;
|
|
|
|
battery_full = 50;
|
|
|
|
time_left = -1;
|
|
|
|
break;
|
|
|
|
case 2: /* low */
|
|
|
|
have_battery = 1;
|
|
|
|
have_power = ac_stat;
|
|
|
|
battery_full = 25;
|
|
|
|
time_left = -1;
|
|
|
|
break;
|
|
|
|
case 3: /* charging */
|
|
|
|
have_battery = 1;
|
|
|
|
have_power = ac_stat;
|
|
|
|
battery_full = 100;
|
|
|
|
time_left = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***---***/
|
|
|
|
/* for older mac powerbooks. legacy as well like linux_apm_init/check. leave
|
|
|
|
* it alone unless you have to touch it */
|
|
|
|
static void linux_pmu_init(void);
|
|
|
|
static void linux_pmu_check(void);
|
|
|
|
|
|
|
|
static void
|
|
|
|
linux_pmu_init(void)
|
|
|
|
{
|
|
|
|
/* nothing to do */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
linux_pmu_check(void)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
char buf[4096];
|
|
|
|
Ecore_List *bats;
|
|
|
|
char *name;
|
|
|
|
int ac = 0;
|
|
|
|
int flags = 0;
|
|
|
|
int charge = 0;
|
|
|
|
int max_charge = 0;
|
|
|
|
int voltage = 0;
|
|
|
|
int seconds = 0;
|
|
|
|
int curcharge = 0;
|
|
|
|
int curmax = 0;
|
|
|
|
|
|
|
|
f = fopen("/proc/pmu/info", "r");
|
|
|
|
if (f)
|
|
|
|
{
|
|
|
|
/* Skip driver */
|
|
|
|
fgets(buf, sizeof(buf), f);
|
|
|
|
/* Skip firmware */
|
|
|
|
fgets(buf, sizeof(buf), f);
|
|
|
|
/* Read ac */
|
|
|
|
fgets(buf, sizeof(buf), f); buf[sizeof(buf) - 1] = 0;
|
|
|
|
ac = int_get(buf);
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
bats = ecore_file_ls("/proc/pmu");
|
|
|
|
if (bats)
|
|
|
|
{
|
|
|
|
have_battery = 1;
|
|
|
|
have_power = ac;
|
|
|
|
while ((name = ecore_list_next(bats)))
|
|
|
|
{
|
|
|
|
if (strncmp(name, "battery", 7)) continue;
|
|
|
|
snprintf(buf, sizeof(buf), "/proc/pmu/%s", name);
|
|
|
|
f = fopen(buf, "r");
|
|
|
|
if (f)
|
|
|
|
{
|
|
|
|
int timeleft = 0;
|
|
|
|
int current = 0;
|
|
|
|
|
|
|
|
while (fgets(buf,sizeof (buf), f))
|
|
|
|
{
|
|
|
|
char *token;
|
|
|
|
|
|
|
|
if ((token = strtok(buf, ":")))
|
|
|
|
{
|
|
|
|
if (!strncmp("flags", token, 5))
|
|
|
|
flags = axtoi(strtok (0, ": "));
|
|
|
|
else if (!strncmp("charge", token, 6))
|
|
|
|
charge = atoi(strtok(0, ": "));
|
|
|
|
else if (!strncmp("max_charge", token, 9))
|
|
|
|
max_charge = atoi(strtok(0, ": "));
|
|
|
|
else if (!strncmp("current", token, 7))
|
|
|
|
current = atoi(strtok(0, ": "));
|
|
|
|
else if (!strncmp("time rem", token, 8))
|
|
|
|
timeleft = atoi(strtok(0, ": "));
|
|
|
|
else if (!strncmp("voltage", token, 7))
|
|
|
|
voltage = atoi(strtok(0, ": "));
|
|
|
|
else
|
|
|
|
strtok(0, ": ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
curmax += max_charge;
|
|
|
|
curcharge += charge;
|
|
|
|
fclose(f);
|
|
|
|
if (!current)
|
|
|
|
{
|
|
|
|
/* Neither charging nor discharging */
|
|
|
|
}
|
|
|
|
else if (!ac)
|
|
|
|
{
|
|
|
|
/* When on dc, we are discharging */
|
|
|
|
seconds += timeleft;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Charging - works in paralell */
|
|
|
|
seconds = MAX(timeleft, seconds);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ecore_list_destroy(bats);
|
2008-03-03 19:35:03 -08:00
|
|
|
if (max_charge > 0) battery_full = ((long long)charge * 100) / max_charge;
|
2008-03-03 01:48:37 -08:00
|
|
|
else battery_full = 0;
|
|
|
|
time_left = seconds;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
have_power = ac;
|
|
|
|
have_battery = 0;
|
|
|
|
battery_full = -1;
|
|
|
|
time_left = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
init(void)
|
|
|
|
{
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
int acline;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
len = sizeof(acline);
|
|
|
|
if (!sysctlbyname("hw.acpi.acline", &acline, &len, NULL, 0))
|
|
|
|
{
|
|
|
|
int acline_mib[3] = {-1};
|
|
|
|
|
|
|
|
len = 3;
|
|
|
|
if (!sysctlnametomib("hw.acpi.acline", acline_mib, &len))
|
|
|
|
{
|
|
|
|
mode = CHECK_ACPI;
|
|
|
|
bsd_acpi_init();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (ecore_file_exists("/dev/apm"))
|
|
|
|
{
|
|
|
|
mode = CHECK_APM;
|
|
|
|
bsd_apm_init();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#elif defined(HAVE_CFBASE_H) /* OS X */
|
|
|
|
darwin_init();
|
|
|
|
#else
|
|
|
|
if (ecore_file_is_dir("/sys/class/power_supply")) /* >= 2.6.24 */
|
|
|
|
{
|
|
|
|
mode = CHECK_SYS_CLASS_POWER_SUPPLY;
|
|
|
|
linux_sys_class_power_supply_init();
|
|
|
|
}
|
|
|
|
else if (ecore_file_is_dir("/proc/acpi")) /* <= 2.6.24 */
|
|
|
|
{
|
|
|
|
mode = CHECK_ACPI;
|
|
|
|
linux_acpi_init();
|
|
|
|
}
|
|
|
|
else if (ecore_file_exists("/proc/apm"))
|
|
|
|
{
|
|
|
|
mode = CHECK_APM;
|
|
|
|
linux_apm_init();
|
|
|
|
}
|
|
|
|
else if (ecore_file_is_dir("/proc/pmu"))
|
|
|
|
{
|
|
|
|
mode = CHECK_PMU;
|
|
|
|
linux_pmu_init();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
poll_cb(void *data)
|
|
|
|
{
|
|
|
|
int ptime_left;
|
|
|
|
int pbattery_full;
|
|
|
|
int phave_battery;
|
|
|
|
int phave_power;
|
|
|
|
|
|
|
|
ptime_left = time_left;
|
|
|
|
pbattery_full = battery_full;
|
|
|
|
phave_battery = have_battery;
|
|
|
|
phave_power = have_power;
|
|
|
|
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case CHECK_ACPI:
|
|
|
|
bsd_acpi_check();
|
|
|
|
break;
|
|
|
|
case CHECK_APM:
|
|
|
|
bsd_apm_check();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
battery_full = -1;
|
|
|
|
time_left = -1;
|
|
|
|
have_battery = 0;
|
|
|
|
have_power = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#elif defined(HAVE_CFBASE_H) /* OS X */
|
|
|
|
darwin_check();
|
|
|
|
break;
|
|
|
|
#else
|
|
|
|
switch (mode)
|
|
|
|
{
|
|
|
|
case CHECK_ACPI:
|
|
|
|
linux_acpi_check();
|
|
|
|
break;
|
|
|
|
case CHECK_APM:
|
|
|
|
linux_apm_check();
|
|
|
|
break;
|
|
|
|
case CHECK_PMU:
|
|
|
|
linux_pmu_check();
|
|
|
|
break;
|
|
|
|
case CHECK_SYS_CLASS_POWER_SUPPLY:
|
|
|
|
linux_sys_class_power_supply_check();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
battery_full = -1;
|
|
|
|
time_left = -1;
|
|
|
|
have_battery = 0;
|
|
|
|
have_power = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if ((ptime_left != time_left) ||
|
|
|
|
(pbattery_full != battery_full) ||
|
|
|
|
(phave_battery != have_battery) ||
|
|
|
|
(phave_power != have_power))
|
|
|
|
{
|
|
|
|
if ((time_left < 0) &&
|
|
|
|
((have_battery) && (battery_full < 0)))
|
|
|
|
printf("ERROR\n");
|
|
|
|
else
|
|
|
|
printf("%i %i %i %i\n",
|
|
|
|
battery_full, time_left, have_battery, have_power);
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
if (argc != 2)
|
|
|
|
{
|
|
|
|
printf("ARGS INCORRECT!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
poll_interval = atoi(argv[1]);
|
|
|
|
|
|
|
|
ecore_init();
|
|
|
|
ecore_file_init();
|
|
|
|
ecore_con_init();
|
|
|
|
|
|
|
|
init();
|
|
|
|
poller = ecore_poller_add(ECORE_POLLER_CORE, poll_interval, poll_cb, NULL);
|
|
|
|
poll_cb(NULL);
|
|
|
|
|
|
|
|
ecore_main_loop_begin();
|
|
|
|
|
|
|
|
ecore_con_shutdown();
|
|
|
|
ecore_file_shutdown();
|
|
|
|
ecore_shutdown();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|