diff --git a/ksysguardd/Linux/acpi.c b/ksysguardd/Linux/acpi.c --- a/ksysguardd/Linux/acpi.c +++ b/ksysguardd/Linux/acpi.c @@ -27,21 +27,25 @@ #include #include #include +#include +#include #include "Command.h" #include "ksysguardd.h" #include "acpi.h" -#define ACPIFILENAMELENGTHMAX 64 +#define ACPIFILEBUFFSIZE 1024 +#define ACPIFILENAMELENGTHMAX 1024 #define ACPIBATTERYNUMMAX 6 #define ACPIBATTERYINFOBUFSIZE 1024 #define ACPIBATTERYSTATEBUFSIZE 512 static int AcpiBatteryNum = 0; -static char AcpiBatteryNames[ ACPIBATTERYNUMMAX ][ 8 ]; +static char AcpiBatteryNames[ ACPIBATTERYNUMMAX ][ 64 ]; static int AcpiBatteryCharge[ ACPIBATTERYNUMMAX ]; static int AcpiBatteryUsage[ ACPIBATTERYNUMMAX ]; +static int AcpiProcfsPower = 0; static int AcpiBatteryOk = 1; /* @@ -69,35 +73,130 @@ /************ ACPI Battery **********/ +int readFile(const char* filePath, char* buff, int buffsize) +{ + int fd; + int n; + + if ((fd = open(filePath, O_RDONLY)) < 0) { + log_error("Cannot open file %s", filePath); + return 1; + } + + if ((n = read(fd, buff, buffsize - 1)) == buffsize - 1) { + log_error("Internal buffer too small to read %s", filePath); + close(fd); + return 1; + } + + buff[n] = '\0'; + + close(fd); + + if (n == -1) { + log_error("Failed reading %s", filePath); + return 1; + } + + return 0; +} + +long readFileLong(const char* filePath) +{ + long val; + char buffer[ACPIBATTERYINFOBUFSIZE]; + + if (readFile(filePath, buffer, sizeof(buffer)) != 0) + return -1; + + val = strtol(buffer, NULL, 10); + if (errno == ERANGE) { + log_error("Failed to read value in %s", filePath); + return -1; + } + + return val; +} + +void strip(char* s) +{ + int i, j; + int length = strlen(s); + char* d = s; + for (i = 0, j = 0; i < length; i++) { + if (s[i] == ' ') + d[j++] = '_'; + else if (s[i] != '\n') + d[j++] = s[i]; + } + + d[j] = '\0'; +} + + + void initAcpiBattery( struct SensorModul* sm ) { DIR *d; struct dirent *de; char s[ ACPIFILENAMELENGTHMAX ]; - - if ( ( d = opendir( "/proc/acpi/battery" ) ) == NULL ) { - AcpiBatteryNum = -1; - AcpiBatteryOk = 0; - return; - } else { - AcpiBatteryNum = 0; - AcpiBatteryOk = 1; + char modelName[ ACPIFILEBUFFSIZE ]; + + /* Newer API first */ +#define POWER_SUPPLY_DIR "/sys/class/power_supply" + if ((d = opendir(POWER_SUPPLY_DIR)) != NULL ) { + AcpiBatteryNum = 0; + AcpiProcfsPower = 0; + while ((de = readdir(d))) { + if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) { + char filePath[1024]; + snprintf(filePath, sizeof(filePath), POWER_SUPPLY_DIR "/%s/charge_full", de->d_name); + if (access(filePath, F_OK) == -1) + continue; + snprintf(filePath, sizeof(filePath), POWER_SUPPLY_DIR "/%s/charge_now", de->d_name); + if (access(filePath, F_OK) == -1) + continue; + snprintf(filePath, sizeof(filePath), POWER_SUPPLY_DIR "/%s/model_name", de->d_name); + if (access(filePath, F_OK) == -1) + continue; + if (readFile(filePath, modelName, sizeof(modelName)) != 0) + strncpy(modelName, "Unknown", strlen("Unknown") + 1); + else + strip(modelName); + strncpy(AcpiBatteryNames[AcpiBatteryNum], de->d_name, sizeof(AcpiBatteryNames[0])); + snprintf(s, sizeof(s), "acpi/battery/(%d)_%s/batterycharge", AcpiBatteryNum, modelName); + registerMonitor(s, "integer", printAcpiBatFill, printAcpiBatFillInfo, sm); + snprintf(s, sizeof(s), "acpi/battery/(%d)_%s/batteryusage", AcpiBatteryNum, modelName); + registerMonitor(s, "integer", printAcpiBatUsage, printAcpiBatUsageInfo, sm); + AcpiBatteryCharge[AcpiBatteryNum] = 0; + AcpiBatteryUsage[AcpiBatteryNum] = 0; + AcpiBatteryNum++; + } + } + AcpiBatteryOk = (AcpiBatteryNum > 0); + closedir( d ); + } else if ( ( d = opendir( "/proc/acpi/battery" ) ) != NULL ) { + AcpiBatteryNum = 0; + AcpiBatteryOk = 1; + AcpiProcfsPower = 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++; - } + strncpy( AcpiBatteryNames[ AcpiBatteryNum ], de->d_name, sizeof(AcpiBatteryNames[0]) ); + 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 ); + } else { + AcpiBatteryNum = -1; + AcpiBatteryOk = 0; } } - -int updateAcpiBattery( void ) +int updateProcfsBattery(void) { int i, fd; char s[ ACPIFILENAMELENGTHMAX ]; @@ -108,9 +207,6 @@ 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 ] ); @@ -183,38 +279,72 @@ return 0; } +int updateAcpiBattery( void ) +{ + int i; + double full, now, current; + char s[ACPIFILENAMELENGTHMAX]; + + if (AcpiBatteryNum <= 0) + return -1; + if (!AcpiBatteryOk) + return -1; + if (AcpiProcfsPower) + return updateProcfsBattery(); + + for (i = 0; i < AcpiBatteryNum; i++) { + snprintf(s, sizeof(s), POWER_SUPPLY_DIR "/%s/charge_full", AcpiBatteryNames[i]); + full = readFileLong(s); + + snprintf(s, sizeof(s), POWER_SUPPLY_DIR "/%s/charge_now", AcpiBatteryNames[i]); + now = readFileLong(s); + + snprintf(s, sizeof(s), POWER_SUPPLY_DIR "/%s/current_now", AcpiBatteryNames[i]); + current = readFileLong(s); + + if (now >= 0 && full > 0) + AcpiBatteryCharge[i] = full > 0 ? (int)round((now/full)*100) : 0; + if (current > 0) + AcpiBatteryUsage[i] = (int)round(current); + } + + AcpiBatteryOk = 1; + return 0; +} + +#define OFFSET (AcpiProcfsPower ? 13 : 14) + void printAcpiBatFill( const char* cmd ) { int i; - sscanf( cmd + 13, "%d", &i ); + sscanf( cmd + OFFSET, "%d", &i ); output( "%d\n", AcpiBatteryCharge[ i ] ); } void printAcpiBatFillInfo( const char* cmd ) { int i; - sscanf( cmd + 13, "%d", &i ); + sscanf( cmd + OFFSET, "%d", &i ); output( "Battery %d charge\t0\t100\t%%\n", i ); } void printAcpiBatUsage( const char* cmd) { int i; - sscanf( cmd + 13, "%d", &i ); + sscanf( cmd + OFFSET, "%d", &i ); output( "%d\n", AcpiBatteryUsage[ i ] ); } void printAcpiBatUsageInfo( const char* cmd) { + int i; - int i; - - sscanf(cmd+13, "%d", &i); - - output( "Battery %d usage\t0\t2500\tmA\n", i ); + sscanf(cmd + OFFSET, "%d", &i); + output( "Battery %d usage\t0\t\t%s\n", + i, (AcpiProcfsPower ? "mA" : "µA") ); } /************** ACPI Thermal *****************/