libacpi: libacpi.c Source File

- Main Page
- Classes
- Files

- File List
- File Members

# libacpi.c

Go to the documentation of this file.

    00001 /*
    00002  * (C)opyright 2007 Nico Golde <nico@ngolde.de>
    00003  * See LICENSE file for license details
    00004  */
    00005
    00006 #include <stdio.h>
    00007 #include <stdlib.h>
    00008 #include <unistd.h>
    00009 #include <string.h>
    00010 #include <dirent.h>
    00011 #include <ctype.h>
    00012 #include <stddef.h>
    00013
    00014 #include "libacpi.h"
    00015 #include "list.h"
    00016
    00017 static int read_acpi_battinfo(const int num);
    00018 static int read_acpi_battalarm(const int num);
    00019 static int read_acpi_battstate(const int num);
    00020 static void read_acpi_thermalzones(global_t *globals);
    00021
    00022 typedef struct {
    00023         char * value;
    00024         size_t offset;
    00025 } acpi_value_t;
    00026
    00027 static acpi_value_t
    00028 battinfo_values[] = {
    00029         { "last full capacity:", offsetof(battery_t, last_full_cap) },
    00030         { "design voltage:", offsetof(battery_t, design_voltage) },
    00031         { "design capacity warning:", offsetof(battery_t, design_warn) },
    00032         { "design capacity low:", offsetof(battery_t, design_low) },
    00033         { "capacity granularity 1:", offsetof(battery_t, design_level1) },
    00034         { "capacity granularity 2:", offsetof(battery_t, design_level2) },
    00035         { NULL, 0 }
    00036 };
    00037
    00038 static acpi_value_t
    00039 battstate_values[] = {
    00040         { "present rate:", offsetof(battery_t, present_rate) },
    00041         { "remaining capacity:", offsetof(battery_t, remaining_cap) },
    00042         { "present voltage:", offsetof(battery_t, present_voltage) },
    00043         { NULL, 0 }
    00044 };
    00045
    00046 /* given a buffer for example from a file, search for key
    00047  * and return a pointer to the value of it. On error return NULL*/
    00048 static char *
    00049 scan_acpi_value(const char *buf, const char *key){
    00050         char *ptr = NULL;
    00051         char *tmpbuf = NULL;
    00052         char *tmpkey = NULL;
    00053         char *tmpval = NULL;
    00054
    00055         if((tmpbuf = strdup(buf)) == NULL)
    00056                 return NULL;
    00057
    00058         /* jump to the key in buffer */
    00059         if((tmpkey = strstr(tmpbuf, key))) {
    00060                 /* jump behind the key, whitespaces and tabs */
    00061                 for(tmpkey += strlen(key); *tmpkey && (*tmpkey == ' ' || *tmpkey == '\t'); tmpkey++);
    00062                 for(tmpval = tmpkey; *tmpval && *tmpval != ' ' &&
    00063                                 *tmpval != '\t' && *tmpval != '\n' &&
    00064                                 *tmpval != '\r'; tmpval++);
    00065                 if(tmpval)
    00066                         *tmpval = '\0';
    00067
    00068                 if((ptr = strdup(tmpkey)) == NULL) {
    00069                         free(tmpbuf);
    00070                         return NULL;
    00071                 }
    00072         }
    00073         free(tmpbuf);
    00074         return ptr;
    00075 }
    00076
    00077 /* reads a file into a buffer and returns a pointer to it, or NULL on error */
    00078 static char *
    00079 get_acpi_content(const char *file){
    00080         FILE *input = NULL;
    00081         char *buf = NULL;
    00082         int read = 0;
    00083
    00084         if((buf = malloc(MAX_BUF + 1)) == NULL)
    00085                 return NULL;
    00086         if((input = fopen(file, "r")) == NULL)
    00087                 return NULL;
    00088
    00089         read = fread(buf, 1, MAX_BUF, input);
    00090         if(read > 0) buf[read - 1] = '\0';
    00091         else buf[0] = '\0'; /* I would consider it a kernel bug if that happens */
    00092
    00093         fclose(input);
    00094         return buf;
    00095 }
    00096
    00097 /* returns the acpi version or NOT_SUPPORTED(negative value) on failure */
    00098 static int
    00099 get_acpi_version(void){
    00100         long ret = -1;
    00101         char *tmp = get_acpi_content(PROC_ACPI "info");
    00102         char *version = NULL;
    00103
    00104         if(!tmp) {
    00105                 tmp = get_acpi_content("/sys/module/acpi/parameters/acpica_version");
    00106                 if (tmp) {
    00107                         long ret = strtol(tmp, NULL, 10);
    00108                         free(tmp);
    00109                         return ret;
    00110                 } else {
    00111                         return NOT_SUPPORTED;
    00112                 }
    00113         }
    00114         if((version = scan_acpi_value(tmp, "version:")) == NULL){
    00115                 free(tmp);
    00116                 return NOT_SUPPORTED;
    00117         }
    00118         ret = strtol(version, NULL, 10);
    00119         free(tmp);
    00120         free(version);
    00121         return ret;
    00122 }
    00123
    00124 /* check if acpi is supported on the system, return 0 on success
    00125  * and -1 if not */
    00126 int
    00127 check_acpi_support(void){
    00128         int version = get_acpi_version();
    00129
    00130         /* we don't support 2.4 kernel versions TODO */
    00131         if(version == NOT_SUPPORTED || version < 20020214)
    00132                 return NOT_SUPPORTED;
    00133         return SUCCESS;
    00134 }
    00135
    00136 /* reads existent battery directories and starts to fill the battery
    00137  * structure. Returns 0 on success, negative values on error */
    00138 int
    00139 init_acpi_batt(global_t *globals){
    00140         char *names[MAX_ITEMS];
    00141         battery_t *binfo;
    00142         list_t *lst = NULL;
    00143         node_t *node = NULL;
    00144         int i = 0;
    00145
    00146         globals->batt_count = 0;
    00147         if((lst = dir_list(PROC_ACPI "battery")) == NULL || !lst->top)
    00148                 return NOT_SUPPORTED;
    00149         for(node = lst->top; node; node=node->next){
    00150                 if((names[globals->batt_count] = strdup(node->name)) == NULL){
    00151                         delete_list(lst);
    00152                         return ALLOC_ERR;
    00153                 }
    00154                 globals->batt_count++;
    00155         }
    00156
    00157         if(globals->batt_count > MAX_ITEMS) return ITEM_EXCEED;
    00158
    00159         /* A quick insertion sort, to sort battery names */
    00160         {
    00161                 char *tmp1, *tmp2;
    00162                 int x,y;
    00163                 for (x = 1; x < globals->batt_count; x++) {
    00164                         tmp1 = names[x];
    00165                         y = x - 1;
    00166                         while ((y >= 0) && ((strcmp (tmp1, names[y])) < 0)) {
    00167                                 tmp2 = names[y + 1];
    00168                                 names[y + 1] = names[y];
    00169                                 names[y] = tmp2;
    00170                         }
    00171                 }
    00172         }
    00173
    00174         for (i=0; i < globals->batt_count && i < MAX_ITEMS; i++){
    00175                 binfo = &batteries[i];
    00176                 snprintf(binfo->name, MAX_NAME, "%s", names[i]);
    00177                 snprintf(binfo->state_file, MAX_NAME, PROC_ACPI "battery/%s/state", names[i]);
    00178                 snprintf(binfo->info_file, MAX_NAME, PROC_ACPI "battery/%s/info", names[i]);
    00179                 snprintf(binfo->alarm_file, MAX_NAME, PROC_ACPI "battery/%s/alarm", names[i]);
    00180                 read_acpi_battinfo(i);
    00181                 read_acpi_battalarm(i);
    00182                 free(names[i]);
    00183         }
    00184         delete_list(lst);
    00185         return SUCCESS;
    00186 }
    00187
    00188 /* reads the acpi state and writes it into the globals structure, void */
    00189 void
    00190 read_acpi_acstate(global_t *globals){
    00191         adapter_t *ac = &globals->adapt;
    00192         char *buf = NULL;
    00193         char *tmp = NULL;
    00194
    00195         if(ac->state_file && (buf = get_acpi_content(ac->state_file)) == NULL){
    00196                 ac->ac_state = P_ERR;
    00197                 return;
    00198         }
    00199         if((tmp = scan_acpi_value(buf, "state:")) && !strncmp(tmp, "on-line", 7))
    00200                 ac->ac_state = P_AC;
    00201         else if(tmp && !strncmp(tmp, "off-line", 8))
    00202                 ac->ac_state = P_BATT;
    00203         else ac->ac_state = P_ERR;
    00204         free(buf);
    00205         free(tmp);
    00206 }
    00207
    00208 /* reads the name of the ac-adapter directory and fills the adapter_t
    00209  * structure with the name and the state-file. Return 0 on success, negative values on errors */
    00210 int
    00211 init_acpi_acadapt(global_t *globals){
    00212         list_t *lst = NULL;
    00213         adapter_t *ac = &globals->adapt;
    00214
    00215         if((lst = dir_list(PROC_ACPI "ac_adapter")) == NULL || !lst->top)
    00216                 return NOT_SUPPORTED;
    00217
    00218         if((!lst->top->name || ((ac->name = strdup(lst->top->name)) == NULL))){
    00219                 delete_list(lst);
    00220                 return ALLOC_ERR;
    00221         }
    00222         snprintf(ac->state_file, MAX_NAME, PROC_ACPI "ac_adapter/%s/state", ac->name);
    00223         delete_list(lst);
    00224         read_acpi_acstate(globals);
    00225         return SUCCESS;
    00226 }
    00227
    00228 /* read acpi information for fan num, returns 0 on success and negative values on errors */
    00229 int
    00230 read_acpi_fan(const int num){
    00231         char *buf = NULL;
    00232         char *tmp = NULL;
    00233         fan_t *info = &fans[num];
    00234
    00235         if(num > MAX_ITEMS) return ITEM_EXCEED;
    00236
    00237         /* scan state file */
    00238         if((buf = get_acpi_content(info->state_file)) == NULL)
    00239                 info->fan_state = F_ERR;
    00240
    00241         if(!buf || (tmp = scan_acpi_value(buf, "status:")) == NULL){
    00242                 info->fan_state = F_ERR;
    00243                 return NOT_SUPPORTED;
    00244         }
    00245         if (tmp[0] == 'o' && tmp[1] == 'n') info->fan_state = F_ON;
    00246         else if(tmp[0] == 'o' && tmp[1] == 'f') info->fan_state = F_OFF;
    00247         else info->fan_state = F_ERR;
    00248         free(buf);
    00249         free(tmp);
    00250         return SUCCESS;
    00251 }
    00252
    00253 /* read all fans, fill the fan structures */
    00254 static void
    00255 read_acpi_fans(global_t *globals){
    00256         int i;
    00257         for(i = 0; i < globals->fan_count; i++)
    00258                 read_acpi_fan(i);
    00259 }
    00260
    00261 /* reads the names of the fan directories, fills fan_t,
    00262  * return 0 on success, negative values on errors */
    00263 int
    00264 init_acpi_fan(global_t *globals){
    00265         char *names[MAX_ITEMS];
    00266         list_t *lst = NULL;
    00267         node_t *node = NULL;
    00268         int i = 0;
    00269         fan_t *finfo = NULL;
    00270         globals->fan_count = 0;
    00271
    00272         if((lst = dir_list(PROC_ACPI "fan")) == NULL || !lst->top)
    00273                 return NOT_SUPPORTED;
    00274         for(node = lst->top; node; node = node->next){
    00275                 if((names[globals->fan_count] = strdup(node->name)) == NULL){
    00276                         delete_list(lst);
    00277                         return ALLOC_ERR;
    00278                 }
    00279                 globals->fan_count++;
    00280         }
    00281
    00282         if(globals->fan_count > MAX_ITEMS) return ITEM_EXCEED;
    00283
    00284         for (; i < globals->fan_count && i < MAX_ITEMS; i++){
    00285                 finfo = &fans[i];
    00286                 snprintf(finfo->name, MAX_NAME, "%s", names[i]);
    00287                 snprintf(finfo->state_file, MAX_NAME, PROC_ACPI "fan/%s/state", names[i]);
    00288                 free(names[i]);
    00289         }
    00290         delete_list(lst);
    00291         read_acpi_fans(globals);
    00292         return SUCCESS;
    00293 }
    00294
    00295 /* reads the name of the thermal-zone directory and fills the adapter_t
    00296  * structure with the name and the state-file. Return 0 on success, negative values on errors */
    00297 int
    00298 init_acpi_thermal(global_t *globals){
    00299         char *names[MAX_ITEMS];
    00300         list_t *lst = NULL;
    00301         node_t *node = NULL;
    00302         thermal_t *tinfo = NULL;
    00303         int i = 0;
    00304         globals->thermal_count = 0;
    00305
    00306         if((lst = dir_list(PROC_ACPI "thermal_zone")) == NULL)
    00307                 return NOT_SUPPORTED;
    00308         for(node = lst->top; node; node = node->next){
    00309                 if((names[globals->thermal_count] = strdup(node->name)) == NULL){
    00310                         delete_list(lst);
    00311                         return ALLOC_ERR;
    00312                 }
    00313                 globals->thermal_count++;
    00314         }
    00315
    00316         if(globals->thermal_count > MAX_ITEMS) return ITEM_EXCEED;
    00317
    00318         for (; i < globals->thermal_count && i < MAX_ITEMS; i++){
    00319                 tinfo = &thermals[i];
    00320                 snprintf(tinfo->name, MAX_NAME, "%s", names[i]);
    00321                 snprintf(tinfo->state_file, MAX_NAME, PROC_ACPI "thermal_zone/%s/state", names[i]);
    00322                 snprintf(tinfo->temp_file, MAX_NAME, PROC_ACPI "thermal_zone/%s/temperature", names[i]);
    00323                 snprintf(tinfo->cooling_file, MAX_NAME, PROC_ACPI "thermal_zone/%s/cooling_mode", names[i]);
    00324                 snprintf(tinfo->freq_file, MAX_NAME, PROC_ACPI "thermal_zone/%s/polling_frequency", names[i]);
    00325                 snprintf(tinfo->trips_file, MAX_NAME, PROC_ACPI "thermal_zone/%s/trip_points", names[i]);
    00326                 free(names[i]);
    00327         }
    00328         delete_list(lst);
    00329         read_acpi_thermalzones(globals);
    00330         return SUCCESS;
    00331 }
    00332
    00333 /* checks the string state and sets the thermal state, returns void */
    00334 static void
    00335 thermal_state(const char *state, thermal_t *info){
    00336         if(state[0] == 'o')
    00337                 info->therm_state = T_OK;
    00338         else if(!strncmp (state, "crit", 4))
    00339                 info->therm_state = T_CRIT;
    00340         else if (!strncmp (state, "hot", 3))
    00341                 info->therm_state = T_HOT; else if (!strncmp (state, "pas", 3))
    00342                 info->therm_state = T_PASS;
    00343         else
    00344                 info->therm_state = T_ACT;
    00345 }
    00346
    00347 /* checks the string tmp and sets the cooling mode */
    00348 static void
    00349 fill_cooling_mode(const char *tmp, thermal_t *info){
    00350         if(tmp[0] == 'a')
    00351                 info->therm_mode = CO_ACT;
    00352         else if(tmp[0]  == 'p')
    00353                 info->therm_mode = CO_PASS;
    00354         else info->therm_mode = CO_CRIT;
    00355 }
    00356
    00357 /* reads values for thermal_zone num, return 0 on success, negative values on error */
    00358 int
    00359 read_acpi_zone(const int num, global_t *globals){
    00360         char *buf = NULL;
    00361         char *tmp = NULL;
    00362         thermal_t *info = &thermals[num];
    00363
    00364         if(num > MAX_ITEMS) return ITEM_EXCEED;
    00365
    00366         /* scan state file */
    00367         if((buf = get_acpi_content(info->state_file)) == NULL)
    00368                 info->therm_state = T_ERR;
    00369
    00370         if(buf && (tmp = scan_acpi_value(buf, "state:")))
    00371                         thermal_state(tmp, info);
    00372         free(tmp);
    00373         free(buf);
    00374
    00375         /* scan temperature file */
    00376         if((buf = get_acpi_content(info->temp_file)) == NULL)
    00377                 info->temperature = NOT_SUPPORTED;
    00378
    00379         if(buf && (tmp = scan_acpi_value(buf, "temperature:"))){
    00380                 info->temperature = strtol(tmp, NULL, 10);
    00381                 /* if we just have one big thermal zone, this will be the global temperature */
    00382                 if(globals->thermal_count == 1)
    00383                         globals->temperature = info->temperature;
    00384         }
    00385         free(tmp);
    00386         free(buf);
    00387
    00388         /* scan cooling mode file */
    00389         if((buf = get_acpi_content(info->cooling_file)) == NULL)
    00390                 info->therm_mode = CO_ERR;
    00391         if(buf && (tmp = scan_acpi_value(buf, "cooling mode:")))
    00392                 fill_cooling_mode(tmp, info);
    00393         else info->therm_mode = CO_ERR;
    00394         free(tmp);
    00395         free(buf);
    00396
    00397         /* scan polling_frequencies file */
    00398         if((buf = get_acpi_content(info->freq_file)) == NULL)
    00399                 info->frequency = DISABLED;
    00400         if(buf && (tmp = scan_acpi_value(buf, "polling frequency:")))
    00401                 info->frequency = strtol(tmp, NULL, 10);
    00402         else info->frequency = DISABLED;
    00403         free(tmp);
    00404         free(buf);
    00405
    00406         /* TODO: IMPLEMENT TRIP POINTS FILE */
    00407
    00408         return SUCCESS;
    00409 }
    00410
    00411 /* read all thermal zones, fill the thermal structures */
    00412 static void
    00413 read_acpi_thermalzones(global_t *globals){
    00414         int i;
    00415         for(i = 0; i < globals->thermal_count; i++)
    00416                 read_acpi_zone(i, globals);
    00417 }
    00418
    00419 /* fill battery_state for given battery, return 0 on success or negative values on error */
    00420 static void
    00421 batt_charge_state(battery_t *info){
    00422         int high = info->last_full_cap / 2;
    00423         int med = high / 2;
    00424
    00425         if(info->remaining_cap > high)
    00426                 info->batt_state = B_HIGH;
    00427         else if(info->remaining_cap <= high && info->remaining_cap > med)
    00428                 info->batt_state = B_MED;
    00429         else if(info->remaining_cap <= med && info->remaining_cap > info->design_warn)
    00430                 info->batt_state = B_LOW;
    00431         else if(info->remaining_cap <= info->design_warn && info->remaining_cap > info->design_low)
    00432                 info->batt_state = B_CRIT;
    00433         else info->batt_state = B_HARD_CRIT;
    00434 }
    00435
    00436 /* fill charge_state of a given battery num, return 0 on success or negative values on error */
    00437 static void
    00438 fill_charge_state(const char *state, battery_t *info){
    00439         if(state[0] == 'u')
    00440                 info->charge_state = C_ERR;
    00441         else if(!strncmp (state, "disch", 5))
    00442                 info->charge_state = C_DISCHARGE;
    00443         else if (!strncmp (state, "charge", 6))
    00444                 info->charge_state = C_CHARGED;
    00445         else if (!strncmp (state, "chargi", 6))
    00446                 info->charge_state = C_CHARGE;
    00447         else
    00448                 info->charge_state = C_NOINFO;
    00449 }
    00450
    00451 /* read alarm capacity, return 0 on success, negative values on error */
    00452 static int
    00453 read_acpi_battalarm(const int num){
    00454         char *buf = NULL;
    00455         char *tmp = NULL;
    00456         battery_t *info = &batteries[num];
    00457
    00458         if((buf = get_acpi_content(info->alarm_file)) == NULL)
    00459                 return NOT_SUPPORTED;
    00460
    00461         if((tmp = scan_acpi_value(buf, "alarm:")) && tmp[0] != 'u')
    00462                 info->alarm = strtol(tmp, NULL, 10);
    00463         else
    00464                 info->alarm = NOT_SUPPORTED;
    00465         free(buf);
    00466         free(tmp);
    00467         return SUCCESS;
    00468 }
    00469
    00470 /* reads static values for a battery (info file), returns SUCCESS */
    00471 static int
    00472 read_acpi_battinfo(const int num){
    00473         char *buf = NULL;
    00474         char *tmp = NULL;
    00475         battery_t *info = &batteries[num];
    00476         int i = 0;
    00477
    00478         if((buf = get_acpi_content(info->info_file)) == NULL)
    00479                 return NOT_SUPPORTED;
    00480
    00481         /* you have to read the present value always since a battery can be taken away while
    00482          * refreshing the data */
    00483         if((tmp = scan_acpi_value(buf, "present:")) && !strncmp(tmp, "yes", 3)) {
    00484                 free(tmp);
    00485                 info->present = 1;
    00486         } else {
    00487                 info->present = 0;
    00488                 free(buf);
    00489                 return NOT_PRESENT;
    00490         }
    00491
    00492         if((tmp = scan_acpi_value(buf, "design capacity:")) && tmp[0] != 'u'){
    00493                 info->design_cap = strtol(tmp, NULL, 10);
    00494                 /* workaround ACPI's broken way of reporting no battery */
    00495                 if(info->design_cap == 655350) info->design_cap = NOT_SUPPORTED;
    00496                 free(tmp);
    00497         }
    00498         else info->design_cap = NOT_SUPPORTED;
    00499
    00500         for (;battinfo_values[i].value; i++) {
    00501                 if ((tmp = scan_acpi_value(buf, battinfo_values[i].value)) && tmp[0] != 'u') {
    00502                         *((int *)(((char *)info) + battinfo_values[i].offset)) = strtol(tmp, NULL, 10);
    00503                         free(tmp);
    00504                 } else {
    00505                         *((int *)(((char *)info) + battinfo_values[i].offset)) = NOT_SUPPORTED;
    00506                 }
    00507         }
    00508
    00509         /* TODO remove debug */
    00510         /* printf("%s\n", buf); */
    00511         free(buf);
    00512
    00513         return SUCCESS;
    00514 }
    00515
    00516 /* read information for battery num, return 0 on success or negative values on error */
    00517 static int
    00518 read_acpi_battstate(const int num){
    00519         char *buf = NULL;
    00520         char *tmp = NULL;
    00521         battery_t *info = &batteries[num];
    00522         unsigned int i = 0;
    00523
    00524         if((buf = get_acpi_content(info->state_file)) == NULL)
    00525                 return NOT_SUPPORTED;
    00526
    00527         if((tmp = scan_acpi_value(buf, "present:")) && !strncmp(tmp, "yes", 3)) {
    00528                 info->present = 1;
    00529                 free(tmp);
    00530         } else {
    00531                 info->present = 0;
    00532                 free(buf);
    00533                 return NOT_PRESENT;
    00534         }
    00535
    00536         /* TODO REMOVE DEBUG */
    00537         /* printf("%s\n\n", buf); */
    00538
    00539         if((tmp = scan_acpi_value(buf, "charging state:")) && tmp[0] != 'u') {
    00540                 fill_charge_state(tmp, info);
    00541                 free(tmp);
    00542         } else {
    00543                 info->charge_state = C_NOINFO;
    00544         }
    00545
    00546         for (;battstate_values[i].value; i++) {
    00547                 if ((tmp = scan_acpi_value(buf, battstate_values[i].value)) && tmp[0] != 'u') {
    00548                         *((int *)(((char *)info) + battstate_values[i].offset)) = strtol(tmp, NULL, 10);
    00549                         free(tmp);
    00550                 } else {
    00551                         *((int *)(((char *)info) + battstate_values[i].offset)) = NOT_SUPPORTED;
    00552                 }
    00553         }
    00554
    00555         /* get information from the info file */
    00556         batt_charge_state(info);
    00557
    00558         free(buf);
    00559         return SUCCESS;
    00560 }
    00561
    00562 /* calculate percentage of battery capacity num */
    00563 static void
    00564 calc_remain_perc(const int num){
    00565         float lfcap;
    00566         battery_t *info = &batteries[num];
    00567         int perc;
    00568
    00569         if(info->remaining_cap < 0){
    00570                 info->percentage = NOT_SUPPORTED;
    00571                 return;
    00572         }
    00573         else{
    00574                 lfcap = info->last_full_cap;
    00575                 if(lfcap <= 0) lfcap = 1;
    00576                 perc = (int) ((info->remaining_cap / lfcap) * 100.0);
    00577         }
    00578         info->percentage = perc > 100 ? 100 : perc;
    00579 }
    00580
    00581 /* calculate remaining charge time for battery num */
    00582 static void
    00583 calc_remain_chargetime(const int num){
    00584         battery_t *info = &batteries[num];
    00585
    00586         if(info->present_rate < 0 || info->charge_state != C_CHARGE){
    00587                 info->charge_time = 0;
    00588                 return;
    00589         }
    00590         info->charge_time = (int) ((((float)info->last_full_cap - (float)info->remaining_cap) / info->present_rate) * 60.0);
    00591 }
    00592
    00593 /* calculate remaining time for battery num */
    00594 static void
    00595 calc_remain_time(const int num){
    00596         battery_t *info = &batteries[num];
    00597
    00598         if(info->present_rate < 0 || info->charge_state != C_DISCHARGE){
    00599                 info->remaining_time = 0;
    00600                 return;
    00601         }
    00602         info->remaining_time = (int) (((float)info->remaining_cap / (float)info->present_rate) * 60.0);
    00603 }
    00604
    00605 /* read/refresh information about a given battery num
    00606  * returns 0 on SUCCESS, negative values on errors */
    00607 int
    00608 read_acpi_batt(const int num){
    00609         if(num > MAX_ITEMS) return ITEM_EXCEED;
    00610         read_acpi_battstate(num);
    00611         read_acpi_battalarm(num);
    00612         calc_remain_perc(num);
    00613         calc_remain_chargetime(num);
    00614         calc_remain_time(num);
    00615         return SUCCESS;
    00616 }