Commit 9022a937 authored by Script Kiddy's avatar Script Kiddy Committed by Arjen Hiemstra
Browse files

Move ACPI battery information from /proc/acpi to /sys

Summary:
Since kernel 2.6.24 in 2008, the /proc/acpi/battery interface is deprecated.
There is for years no updated kernel which wouldn't provide the /sys/class/power_supply/BAT0 in a laptop
This patch removes the useless old path, and uses the sysfs to provide 3 informations :
- current flow in mA (charge or discharge)
- charge percent against last completed full charge
- charge percent against battery by design charge

Ref:
https://cateee.net/lkddb/web-lkddb/ACPI_PROCFS_POWER.html
https://bbs.archlinux.org/viewtopic.php?id=97761

Reviewers: davidedmundson, #plasma, ahiemstra

Reviewed By: ahiemstra

Subscribers: alexde, plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D25018
parent 05e26b28
......@@ -34,16 +34,7 @@
#include "acpi.h"
#define ACPIFILENAMELENGTHMAX 64
#define ACPIBATTERYNUMMAX 6
#define ACPIBATTERYINFOBUFSIZE 1024
#define ACPIBATTERYSTATEBUFSIZE 512
static int AcpiBatteryNum = 0;
static char AcpiBatteryNames[ ACPIBATTERYNUMMAX ][ 8 ];
static int AcpiBatteryCharge[ ACPIBATTERYNUMMAX ];
static int AcpiBatteryUsage[ ACPIBATTERYNUMMAX ];
static int AcpiBatteryOk = 1;
/*
================================ public part =================================
*/
......@@ -54,169 +45,156 @@ void initAcpi(struct SensorModul* sm)
initAcpiThermal(sm);
}
int updateAcpi( void )
{
if (AcpiBatteryOk && AcpiBatteryNum > 0) updateAcpiBattery();
return 0;
}
void exitAcpi( void )
{
AcpiBatteryNum = -1;
AcpiBatteryOk = 0;
}
/************ ACPI Battery **********/
void registerBatteryCharge(int number, struct SensorModul *sm)
{
char name[ ACPIFILENAMELENGTHMAX ];
readTypeFile("/sys/class/power_supply/BAT%d/type", number, name, sizeof(name));
void initAcpiBattery( struct SensorModul* sm )
char sensorName [ ACPIFILENAMELENGTHMAX ];
snprintf(sensorName, sizeof(sensorName), "acpi/Battery/%d-%s/Charge", number, name);
registerMonitor(sensorName, "integer", printSysBatteryCharge,
printSysBatteryChargeInfo, sm);
}
void registerBatteryChargeDesign(int number, struct SensorModul *sm)
{
DIR *d;
struct dirent *de;
char s[ ACPIFILENAMELENGTHMAX ];
char name[ ACPIFILENAMELENGTHMAX ];
readTypeFile("/sys/class/power_supply/BAT%d/type", number, name, sizeof(name));
if ( ( d = opendir( "/proc/acpi/battery" ) ) == NULL ) {
AcpiBatteryNum = -1;
AcpiBatteryOk = 0;
return;
} else {
AcpiBatteryNum = 0;
AcpiBatteryOk = 1;
while ( ( de = readdir( d ) ) )
if ( ( strcmp( de->d_name, "." ) != 0 ) && ( strcmp( de->d_name, ".." ) != 0 ) ) {
strncpy( AcpiBatteryNames[ AcpiBatteryNum ], de->d_name, 8 );
snprintf( s, sizeof( s ), "acpi/battery/%d/batterycharge", AcpiBatteryNum );
registerMonitor( s, "integer", printAcpiBatFill, printAcpiBatFillInfo, sm );
snprintf( s, sizeof( s ), "acpi/battery/%d/batteryusage", AcpiBatteryNum );
registerMonitor( s, "integer", printAcpiBatUsage, printAcpiBatUsageInfo, sm);
AcpiBatteryCharge[ AcpiBatteryNum ] = 0;
AcpiBatteryNum++;
}
closedir( d );
}
char sensorName [ ACPIFILENAMELENGTHMAX ];
snprintf(sensorName, sizeof(sensorName), "acpi/Battery/%d-%s/ChargeDesign", number, name);
registerMonitor(sensorName, "integer", printSysBatteryChargeDesign,
printSysBatteryChargeDesignInfo, sm);
}
void registerBatteryRate(int number, struct SensorModul *sm)
{
char name[ ACPIFILENAMELENGTHMAX ];
readTypeFile("/sys/class/power_supply/BAT%d/type", number, name, sizeof(name));
char sensorName [ ACPIFILENAMELENGTHMAX ];
snprintf(sensorName, sizeof(sensorName), "acpi/Battery/%d-%s/Rate", number, name);
int updateAcpiBattery( void )
registerMonitor(sensorName, "integer", printSysBatteryRate,
printSysBatteryRateInfo, sm);
}
void initAcpiBattery( struct SensorModul* sm )
{
int i, fd;
char s[ ACPIFILENAMELENGTHMAX ];
size_t n;
char AcpiBatInfoBuf[ ACPIBATTERYINFOBUFSIZE ];
char AcpiBatStateBuf[ ACPIBATTERYSTATEBUFSIZE ];
char *p;
int AcpiBatCapacity = 1;
int AcpiBatRemainingCapacity = 0;
if ( AcpiBatteryNum <= 0 )
return -1;
for ( i = 0; i < AcpiBatteryNum; i++ ) {
/* get total capacity */
snprintf( s, sizeof( s ), "/proc/acpi/battery/%s/info", AcpiBatteryNames[ i ] );
if ( ( fd = open( s, O_RDONLY ) ) < 0 ) {
print_error( "Cannot open file \'%s\'!\n"
"Load the battery ACPI kernel module or\n"
"compile it into your kernel.\n", s );
AcpiBatteryOk = 0;
return -1;
}
if ( ( n = read( fd, AcpiBatInfoBuf, ACPIBATTERYINFOBUFSIZE - 1 ) ) ==
ACPIBATTERYINFOBUFSIZE - 1 ) {
log_error( "Internal buffer too small to read \'%s\'", s );
close( fd );
AcpiBatteryOk = 0;
return -1;
}
close( fd );
p = AcpiBatInfoBuf;
if ( p && strstr(p, "ERROR: Unable to read battery") )
return 0; /* If we can't read the battery, reuse the last value */
while ( ( p!= NULL ) && ( sscanf( p, "last full capacity: %d ",
&AcpiBatCapacity ) != 1 ) ) {
p = strchr( p, '\n' );
if ( p )
p++;
DIR *d;
struct dirent *de;
char s[ ACPIFILENAMELENGTHMAX ];
d = opendir("/sys/class/power_supply/");
if (d != NULL) {
while ( (de = readdir(d)) != NULL ) {
if (!de->d_name || de->d_name[0] == '.')
continue;
if (strncmp( de->d_name, "BAT", sizeof("BAT")-1) == 0) {
int number = atoi(de->d_name + (sizeof("BAT")-1));
registerBatteryCharge(number, sm);
registerBatteryChargeDesign(number, sm);
registerBatteryRate(number, sm);
}
}
closedir( d );
}
/* get remaining capacity */
snprintf( s, sizeof( s ), "/proc/acpi/battery/%s/state", AcpiBatteryNames[ i ] );
if ( ( fd = open( s, O_RDONLY ) ) < 0 ) {
print_error( "Cannot open file \'%s\'!\n"
"Load the battery ACPI kernel module or\n"
"compile it into your kernel.\n", s );
AcpiBatteryOk = 0;
return -1;
}
void printSysBatteryCharge(const char *cmd)
{
int zone = 0;
if (sscanf(cmd, "acpi/Battery/%d", &zone) <= 0) {
output("-1\n");
return;
}
if ( ( n = read( fd, AcpiBatStateBuf, ACPIBATTERYSTATEBUFSIZE - 1 ) ) ==
ACPIBATTERYSTATEBUFSIZE - 1 ) {
log_error( "Internal buffer too small to read \'%s\'", s);
close( fd );
AcpiBatteryOk = 0;
return -1;
int charge = getSysFileValue("power_supply", "BAT", zone, "charge_now");
int maximum = getSysFileValue("power_supply", "BAT", zone, "charge_full");
int state = 0;
if ( maximum > 0) {
state = charge * 100 / maximum;
}
close( fd );
p = AcpiBatStateBuf;
while ( ( p!= NULL ) && ( sscanf( p, "remaining capacity: %d ",
&AcpiBatRemainingCapacity ) != 1 ) ) {
p = strchr( p, '\n' );
if ( p )
p++;
if (state > 100) {
state = 100; /* prevent insane numbers with bad hardware */
} else if (state < 0) {
state = 0; /* prevent insane numbers with bad hardware */
}
output( "%d\n", state);
}
/* get current battery usage, (current Current) */
p = AcpiBatStateBuf;
while ( ( p!= NULL ) && ( sscanf( p, "present rate: %d ",
&AcpiBatteryUsage[i] ) != 1 ) ) {
p = strchr( p, '\n' );
if ( p )
p++;
void printSysBatteryChargeInfo(const char *cmd)
{
char name [ 200 ];
if (sscanf(cmd, "acpi/Battery/%199[^/]", name) > 0) {
output( "%s charge\t0\t100\t%%\n", name);
} else {
output( "Current charge\t0\t100\t%%\n");
}
/* calculate charge rate */
if ( AcpiBatCapacity > 0 )
AcpiBatteryCharge[ i ] = AcpiBatRemainingCapacity * 100 / AcpiBatCapacity;
else
AcpiBatteryCharge[ i ] = 0;
}
AcpiBatteryOk = 1;
return 0;
}
void printAcpiBatFill( const char* cmd )
void printSysBatteryChargeDesign(const char *cmd)
{
int i;
int zone = 0;
if (sscanf(cmd, "acpi/Battery/%d", &zone) <= 0) {
output("-1\n");
return;
}
sscanf( cmd + 13, "%d", &i );
output( "%d\n", AcpiBatteryCharge[ i ] );
int charge = getSysFileValue("power_supply", "BAT", zone, "charge_now");
int maximum = getSysFileValue("power_supply", "BAT", zone, "charge_full_design");
int state = 0;
if (maximum > 0) {
state = charge * 100 / maximum;
}
if (state > 100) {
state = 100; /* prevent insane numbers with bad hardware */
} else if (state < 0) {
state = 0; /* prevent insane numbers with bad hardware */
}
output( "%d\n", state);
}
void printAcpiBatFillInfo( const char* cmd )
void printSysBatteryChargeDesignInfo(const char *cmd)
{
int i;
sscanf( cmd + 13, "%d", &i );
output( "Battery %d charge\t0\t100\t%%\n", i );
char name [ 200 ];
if (sscanf(cmd, "acpi/Battery/%199[^/]", name) > 0) {
output( "%s charge (by design)\t0\t100\t%%\n", name);
} else {
output( "Current charge (by design)\t0\t100\t%%\n");
}
}
void printAcpiBatUsage( const char* cmd)
void printSysBatteryRate(const char *cmd)
{
int i;
int zone = 0;
if (sscanf(cmd, "acpi/Battery/%d", &zone) <= 0) {
output("-1\n");
return;
}
sscanf( cmd + 13, "%d", &i );
output( "%d\n", AcpiBatteryUsage[ i ] );
output( "%d\n", getSysFileValue("power_supply", "BAT", zone, "current_now") / 1000);
}
void printAcpiBatUsageInfo( const char* cmd)
void printSysBatteryRateInfo(const char *cmd)
{
int i;
sscanf(cmd+13, "%d", &i);
output( "Battery %d usage\t0\t2500\tmA\n", i );
char name [ 200 ];
if (sscanf(cmd, "acpi/Battery/%199[^/]", name) > 0) {
output( "%s rate\t0\t0\tmA\n", name);
} else {
output( "Current rate\t0\t0\tmA\n");
}
}
/************** ACPI Thermal *****************/
#define OLD_THERMAL_ZONE_DIR "/proc/acpi/thermal_zone"
......@@ -354,11 +332,11 @@ void initAcpiThermal(struct SensorModul *sm)
return;
}
static int getSysFileValue(const char *group, int value, const char *file) {
static int getSysFileValue(const char *className, const char *group, int value, const char *file) {
static int shownError = 0;
char th_file[ ACPIFILENAMELENGTHMAX ];
char input_buf[ 100 ];
snprintf(th_file, sizeof(th_file), "/sys/class/thermal/%s%d/%s",group, value, file);
snprintf(th_file, sizeof(th_file), "/sys/class/%s/%s%d/%s", className, group, value, file);
int fd = open(th_file, O_RDONLY);
if (fd < 0) {
if (!shownError)
......@@ -390,7 +368,7 @@ void printSysThermalZoneTemperature(const char *cmd) {
return;
}
output( "%d\n", getSysFileValue("thermal_zone", zone, "temp") / 1000);
output( "%d\n", getSysFileValue("thermal", "thermal_zone", zone, "temp") / 1000);
}
void printSysCompatibilityThermalZoneTemperature(const char *cmd) {
int zone = 0;
......@@ -398,7 +376,7 @@ void printSysCompatibilityThermalZoneTemperature(const char *cmd) {
output( "-1\n");
return;
}
output( "%d\n", getSysFileValue("thermal_zone", zone, "temp")/1000);
output( "%d\n", getSysFileValue("thermal", "thermal_zone", zone, "temp")/1000);
}
void printCoolingDeviceStateInfo(const char *cmd)
......@@ -418,8 +396,8 @@ void printCoolingDeviceState(const char *cmd) {
output( "-1\n");
return;
}
int current = getSysFileValue("cooling_device", fan, "cur_state");
int maximum = getSysFileValue("cooling_device", fan, "max_state");
int current = getSysFileValue("thermal", "cooling_device", fan, "cur_state");
int maximum = getSysFileValue("thermal", "cooling_device", fan, "max_state");
int state = 0;
if (current > 0 && maximum > 0) {
state = (current * 100) / maximum; /* state is a percentage */
......
......@@ -23,15 +23,16 @@
void initAcpi( struct SensorModul* );
void exitAcpi( void );
int updateAcpi( void );
void initAcpiBattery( struct SensorModul* );
int updateAcpiBattery(void);
void printAcpiBatFill( const char* );
void printAcpiBatFillInfo( const char* );
void printAcpiBatUsage( const char* );
void printAcpiBatUsageInfo( const char* );
void printSysBatteryCharge(const char *cmd);
void printSysBatteryChargeInfo(const char *cmd);
void printSysBatteryChargeDesign(const char *cmd);
void printSysBatteryChargeDesignInfo(const char *cmd);
void printSysBatteryRate(const char *cmd);
void printSysBatteryRateInfo(const char *cmd);
void readTypeFile(const char *fileFormat, int number, char *buffer, int bufferSize);
static int getSysFileValue(const char *class, const char *group, int value, const char *file);
void initAcpiThermal( struct SensorModul * );
void printThermalZoneTemperature(const char *cmd);
void printSysThermalZoneTemperature(const char *cmd);
......
......@@ -124,7 +124,7 @@ typedef int (*IVFunc)( void );
* 7. timeCentiSeconds - Used internally - set to NULLTIME here */
struct SensorModul SensorModulList[] = {
#ifdef OSTYPE_Linux
{ "Acpi", initAcpi, exitAcpi, updateAcpi, NULLVVFUNC, 0, NULLTIME },
{ "Acpi", initAcpi, exitAcpi, NULLIVFUNC, NULLVVFUNC, 0, NULLTIME },
{ "Apm", initApm, exitApm, updateApm, NULLVVFUNC, 0, NULLTIME },
{ "CpuInfo", initCpuInfo, exitCpuInfo, updateCpuInfo, NULLVVFUNC, 0, NULLTIME },
{ "DellLaptop", initI8k, exitI8k, updateI8k, NULLVVFUNC, 0, NULLTIME },
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment