summaryrefslogtreecommitdiffstats
path: root/ksysguard/ksysguardd/Linux/acpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'ksysguard/ksysguardd/Linux/acpi.c')
-rw-r--r--ksysguard/ksysguardd/Linux/acpi.c418
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 <su@su2.info>
+ Copyright (c) 2005 Sirtaj Singh Kang <taj@kde.org> -- 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");
+}
+
+