You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebase/ksysguard/ksysguardd/Linux/acpi.c

419 lines
11 KiB

/*
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 = (char*)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 = (char*)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 = (char*)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 = (char*)strchr(cmd, '/');
if (idx == NULL) return 0;
idx = (char*)strchr(idx+1, '/');
if (idx == NULL) return 0;
*startidx = idx+1;
idx = (char*)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");
}