00001
00002
00003
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
00047
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
00059 if((tmpkey = strstr(tmpbuf, key))) {
00060
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
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';
00092
00093 fclose(input);
00094 return buf;
00095 }
00096
00097
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
00125
00126 int
00127 check_acpi_support(void){
00128 int version = get_acpi_version();
00129
00130
00131 if(version == NOT_SUPPORTED || version < 20020214)
00132 return NOT_SUPPORTED;
00133 return SUCCESS;
00134 }
00135
00136
00137
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
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
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
00209
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
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
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
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
00262
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
00296
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
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
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
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
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
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
00382 if(globals->thermal_count == 1)
00383 globals->temperature = info->temperature;
00384 }
00385 free(tmp);
00386 free(buf);
00387
00388
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
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
00407
00408 return SUCCESS;
00409 }
00410
00411
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
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
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
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
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
00482
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
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
00510
00511 free(buf);
00512
00513 return SUCCESS;
00514 }
00515
00516
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
00537
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
00556 batt_charge_state(info);
00557
00558 free(buf);
00559 return SUCCESS;
00560 }
00561
00562
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
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
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
00606
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 }