diff options
Diffstat (limited to 'ksysguard/ksysguardd/Linux/acpi.c')
-rw-r--r-- | ksysguard/ksysguardd/Linux/acpi.c | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/ksysguard/ksysguardd/Linux/acpi.c b/ksysguard/ksysguardd/Linux/acpi.c new file mode 100644 index 000000000..b3100c363 --- /dev/null +++ b/ksysguard/ksysguardd/Linux/acpi.c @@ -0,0 +1,418 @@ +/* + KSysGuard, the KDE System Guard + + Copyright (c) 2003 Stephan Uhlmann <[email protected]> + Copyright (c) 2005 Sirtaj Singh Kang <[email protected]> -- Battery fixes and Thermal + + This program is free software; you can redistribute it and/or + modify it under the terms of version 2 of the GNU General Public + License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include <dirent.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "Command.h" +#include "ksysguardd.h" + +#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 AcpiThermalZones = -1; +static int AcpiFans = -1; +/* +================================ public part ================================= +*/ + +void initAcpi(struct SensorModul* sm) +{ + initAcpiBattery(sm); + initAcpiFan(sm); + initAcpiThermal(sm); +} + +int updateAcpi( void ) +{ + if (AcpiBatteryNum > 0) updateAcpiBattery(); + if (AcpiFans > 0) updateAcpiFan(); + if (AcpiThermalZones > 0) updateAcpiThermal(); + return 0; +} + +void exitAcpi( void ) +{ + AcpiBatteryNum = -1; + AcpiFans = -1; + AcpiThermalZones = -1; +} + + +/************ ACPI Battery **********/ + +void initAcpiBattery( struct SensorModul* sm ) +{ + DIR *d; + struct dirent *de; + char s[ ACPIFILENAMELENGTHMAX ]; + + if ( ( d = opendir( "/proc/acpi/battery" ) ) == NULL ) { + AcpiBatteryNum = -1; + return; + } else { + AcpiBatteryNum = 0; + 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++; + } + } +} + + +int updateAcpiBattery( void ) +{ + 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 ); + return -1; + } + if ( ( n = read( fd, AcpiBatInfoBuf, ACPIBATTERYINFOBUFSIZE - 1 ) ) == + ACPIBATTERYINFOBUFSIZE - 1 ) { + log_error( "Internal buffer too small to read \'%s\'", s ); + close( fd ); + return -1; + } + close( fd ); + p = AcpiBatInfoBuf; + while ( ( p!= NULL ) && ( sscanf( p, "last full capacity: %d ", + &AcpiBatCapacity ) != 1 ) ) { + p = strchr( p, '\n' ); + if ( p ) + p++; + } + /* 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 ); + return -1; + } + if ( ( n = read( fd, AcpiBatStateBuf, ACPIBATTERYSTATEBUFSIZE - 1 ) ) == + ACPIBATTERYSTATEBUFSIZE - 1 ) { + log_error( "Internal buffer too small to read \'%s\'", s); + close( fd ); + return -1; + } + close( fd ); + p = AcpiBatStateBuf; + while ( ( p!= NULL ) && ( sscanf( p, "remaining capacity: %d ", + &AcpiBatRemainingCapacity ) != 1 ) ) { + p = strchr( p, '\n' ); + if ( p ) + p++; + } + + /* 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++; + } + + + /* calculate charge rate */ + if ( AcpiBatCapacity > 0 ) + AcpiBatteryCharge[ i ] = AcpiBatRemainingCapacity * 100 / AcpiBatCapacity; + else + AcpiBatteryCharge[ i ] = 0; + } + + return 0; +} + +void printAcpiBatFill( const char* cmd ) +{ + int i; + + sscanf( cmd + 13, "%d", &i ); + fprintf( CurrentClient, "%d\n", AcpiBatteryCharge[ i ] ); +} + +void printAcpiBatFillInfo( const char* cmd ) +{ + int i; + + sscanf( cmd + 13, "%d", &i ); + fprintf( CurrentClient, "Battery %d charge\t0\t100\t%%\n", i ); +} + +void printAcpiBatUsage( const char* cmd) +{ + int i; + + sscanf( cmd + 13, "%d", &i ); + fprintf(CurrentClient, "%d\n", AcpiBatteryUsage[ i ] ); +} + +void printAcpiBatUsageInfo( const char* cmd) +{ + + int i; + + sscanf(cmd+13, "%d", &i); + + fprintf(CurrentClient, "Battery %d usage\t0\t2500\tmA\n", i ); +} + +/************** ACPI Thermal *****************/ + +#define THERMAL_ZONE_DIR "/proc/acpi/thermal_zone" +#define TEMPERATURE_FILE "temperature" +#define TEMPERATURE_FILE_MAXLEN 255 + + +/*static char **zone_names = NULL;*/ + +/** Find the thermal zone name from the command. + * Assumes the command is of the form acpi/thermal_zone/<zone name>/... + * @p startidx is set to the start of the zone name. May be set to an + * undefined value if zone name is not found. + * @return length of found name, or 0 if nothing found. + */ +static int extract_zone_name(char **startidx, const char *cmd) +{ + char *idx = NULL; + idx = strchr(cmd, '/'); + if (idx == NULL) return 0; + idx = strchr(idx+1, '/'); + if (idx == NULL) return 0; + *startidx = idx+1; + idx = strchr(*startidx, '/'); + if (idx == NULL) return 0; + return idx - *startidx; +} + +void initAcpiThermal(struct SensorModul *sm) +{ + + char th_ref[ ACPIFILENAMELENGTHMAX ]; + DIR *d = NULL; + struct dirent *de; + + d = opendir(THERMAL_ZONE_DIR); + if (d == NULL) { +/* print_error( "Directory \'" THERMAL_ZONE_DIR + "\' does not exist or is not readable.\n" + "Load the ACPI thermal kernel module or compile it into your kernel.\n" ); +*/ + AcpiThermalZones = -1; + return; + } + + AcpiThermalZones = 0; + while ( (de = readdir(d)) != NULL ) { + if ( ( strcmp( de->d_name, "." ) == 0 ) + || ( strcmp( de->d_name, ".." ) == 0 ) ) { + continue; + } + + AcpiThermalZones++; + snprintf(th_ref, sizeof(th_ref), + "acpi/thermal_zone/%s/temperature", de->d_name); + registerMonitor(th_ref, "integer", printThermalZoneTemperature, + printThermalZoneTemperatureInfo, sm); + } + + return; +} + +int updateAcpiThermal() +{ + /* TODO: stub */ + return 0; +} + +static int getCurrentTemperature(const char *cmd) +{ + char th_file[ ACPIFILENAMELENGTHMAX ]; + char input_buf[ TEMPERATURE_FILE_MAXLEN ]; + char *zone_name = NULL; + int read_bytes = 0, fd = 0, len_zone_name = 0; + int temperature=0; + + len_zone_name = extract_zone_name(&zone_name, cmd); + if (len_zone_name <= 0) return -1; + + snprintf(th_file, sizeof(th_file), + THERMAL_ZONE_DIR "/%.*s/" TEMPERATURE_FILE, + len_zone_name, zone_name); + + fd = open(th_file, O_RDONLY); + if (fd < 0) { + print_error( "Cannot open file \'%s\'!\n" + "Load the thermal ACPI kernel module or\n" + "compile it into your kernel.\n", th_file ); + return -1; + } + + read_bytes = read( fd, input_buf, sizeof(input_buf) - 1 ); + if ( read_bytes == sizeof(input_buf) - 1 ) { + log_error( "Internal buffer too small to read \'%s\'", th_file ); + close( fd ); + return -1; + } + close(fd); + + sscanf(input_buf, "temperature: %d C", &temperature); + return temperature; +} + +void printThermalZoneTemperature(const char *cmd) { + int temperature = getCurrentTemperature(cmd); + fprintf(CurrentClient, "%d\n", temperature); +} + +void printThermalZoneTemperatureInfo(const char *cmd) +{ + fprintf(CurrentClient, "Current temperature\t0\t0\tC\n"); +} + +/********** ACPI Fan State***************/ + +#define FAN_DIR "/proc/acpi/fan" +#define FAN_STATE_FILE "state" +#define FAN_STATE_FILE_MAXLEN 255 + +void initAcpiFan(struct SensorModul *sm) +{ + + char th_ref[ ACPIFILENAMELENGTHMAX ]; + DIR *d = NULL; + struct dirent *de; + + d = opendir(FAN_DIR); + if (d == NULL) { +/* print_error( "Directory \'" THERMAL_ZONE_DIR + "\' does not exist or is not readable.\n" + "Load the ACPI thermal kernel module or compile it into your kernel.\n" ); +*/ + AcpiFans = -1; + return; + } + + AcpiFans = 0; + while ( (de = readdir(d)) != NULL ) { + if ( ( strcmp( de->d_name, "." ) == 0 ) + || ( strcmp( de->d_name, ".." ) == 0 ) ) { + continue; + } + + AcpiFans++; + snprintf(th_ref, sizeof(th_ref), + "acpi/fan/%s/state", de->d_name); + registerMonitor(th_ref, "integer", printFanState, + printFanStateInfo, sm); + } + + return; +} + +int updateAcpiFan() +{ + /* TODO: stub */ + return 0; +} + +static int getFanState(const char *cmd) +{ + char fan_state_file[ ACPIFILENAMELENGTHMAX ]; + char input_buf[ FAN_STATE_FILE_MAXLEN ]; + char *fan_name = NULL; + int read_bytes = 0, fd = 0, len_fan_name = 0; + char fan_state[4]; + + len_fan_name = extract_zone_name(&fan_name, cmd); + if (len_fan_name <= 0) return -1; + + snprintf(fan_state_file, sizeof(fan_state_file), + FAN_DIR "/%.*s/" FAN_STATE_FILE, + len_fan_name, fan_name); + + fd = open(fan_state_file, O_RDONLY); + if (fd < 0) { + print_error( "Cannot open file \'%s\'!\n" + "Load the fan ACPI kernel module or\n" + "compile it into your kernel.\n", fan_state_file ); + return -1; + } + + read_bytes = read( fd, input_buf, sizeof(input_buf) - 1 ); + if ( read_bytes == sizeof(input_buf) - 1 ) { + log_error( "Internal buffer too small to read \'%s\'", fan_state_file ); + close( fd ); + return -1; + } + close(fd); + + sscanf(input_buf, "status: %2s", fan_state); + return (fan_state[1] == 'n') ? 1 : 0; +} + +void printFanState(const char *cmd) { + int fan_state = getFanState(cmd); + fprintf(CurrentClient, "%d\n", fan_state); +} + +void printFanStateInfo(const char *cmd) +{ + fprintf(CurrentClient, "Fan status\t0\t1\tboolean\n"); +} + + |