1 /***************************************************************************
2 libacpi.c - description
5 copyright : (C) 2003 by Noberasco Michele
6 e-mail : 2001s098@educ.disi.unige.it
7 ***************************************************************************/
9 /***************************************************************************
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License for more details. *
21 * You should have received a copy of the GNU General Public License *
22 * along with this program; if not, write to the *
23 * Free Software Foundation, Inc., *
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
26 ***************************************************************************/
28 /***************************************************************************
29 Originally written by Costantino Pistagna for his wmacpimon
30 ***************************************************************************/
41 #include <sys/types.h>
46 #include "power_management.h"
47 #include "lib_utils.h"
50 /* here we put temp stuff read from proc files */
53 static char batteries
[MAXBATT
][128];
54 static char battinfo
[MAXBATT
][128];
55 static char fans
[MAXFANS
][128];
58 void sort(char names
[MAXBATT
][128], int count
)
63 for (i
=0; i
<(count
-1); i
++)
64 for (j
=i
+1; j
<count
; j
++)
65 if (strcmp(names
[j
], names
[i
]) < 0)
67 strcpy(temp
, names
[j
]);
68 strcpy(names
[j
], names
[i
]);
69 strcpy(names
[i
], temp
);
73 /* see if we have ACPI support */
80 /* do proc entries for acpi exist? */
81 if (access("/proc/acpi/info", R_OK
) != 0) return 0;
83 /* now enumerate batteries */
85 battdir
= opendir ("/proc/acpi/battery");
86 if (!battdir
) return 0;
88 while ((batt
= readdir (battdir
)))
93 if (!strcmp (".", name
) || !strcmp ("..", name
)) continue;
95 if (!access("/proc/acpi/battery/1/status", R_OK
))
96 sprintf (batteries
[batt_count
], "/proc/acpi/battery/%s/status", name
);
98 sprintf (batteries
[batt_count
], "/proc/acpi/battery/%s/state", name
);
99 sprintf (battinfo
[batt_count
], "/proc/acpi/battery/%s/info", name
);
105 /* order battery names as readdir doesn't handle that */
108 sort(batteries
, batt_count
);
109 sort(battinfo
, batt_count
);
112 fprintf(stderr
, "libacpi: found %d batter%s\n", batt_count
, (batt_count
== 1) ? "y" : "ies");
118 char *find_acad_proc_file(void)
121 char *basedir
= "/proc/acpi/ac_adapter/";
122 struct dirent
*entry
;
124 dir
= opendir(basedir
);
125 if (!dir
) return NULL
;
127 while ((entry
= readdir(dir
)))
130 char *temp1
, *temp2
, *temp3
;
131 if (!strcmp(entry
->d_name
, "." )) continue;
132 if (!strcmp(entry
->d_name
, "..")) continue;
133 temp1
= StrApp((char**)NULL
, basedir
, entry
->d_name
, "/state", (char*)NULL
);
134 temp2
= StrApp((char**)NULL
, basedir
, entry
->d_name
, "/status", (char*)NULL
);
135 temp3
= StrApp((char**)NULL
, basedir
, entry
->d_name
, "/stats", (char*)NULL
);
137 if (!access(temp1
, R_OK
)) {result
= temp1
; free(temp2
); free(temp3
);}
138 else if (!access(temp2
, R_OK
)) {result
= temp2
; free(temp1
); free(temp3
);}
139 else if (!access(temp3
, R_OK
)) {result
= temp3
; free(temp1
); free(temp2
);}
146 free(temp1
); free(temp2
); free(temp3
);
153 void read_acad_state (ACADstate
*acadstate
)
155 static int searched
= 0;
156 static char *file
= NULL
;
157 static char *where
= NULL
;
162 file
= find_acad_proc_file();
166 if (!(fp
= fopen(file
, "r"))) return;
168 fread_unlocked (buf
, 512, 1, fp
);
173 if (!strncmp(buf
, "state:", 6)) where
= buf
+ 26;
174 if (!strncmp(buf
, "Status:", 7)) where
= buf
+ 26;
178 if (where
[0] == 'n') acadstate
->state
= 1;
179 if (where
[0] == 'f') acadstate
->state
= 0;
183 void read_acpi_info (ACPIinfo
*acpiinfo
, int battery
)
189 if (battery
> MAXBATT
) return;
190 if (!(fp
= fopen (battinfo
[battery
], "r"))) return;
192 fread_unlocked (buf
, 512, 1, fp
);
197 static int count
= 0;
199 if (!strncmp(ptr
+1, "resent:", 7))
201 if (ptr
[offset
] != 'y')
203 acpiinfo
->present
= 0;
204 acpiinfo
->design_capacity
= 0;
205 acpiinfo
->last_full_capacity
= 0;
206 acpiinfo
->battery_technology
= 0;
207 acpiinfo
->design_voltage
= 0;
208 acpiinfo
->design_capacity_warning
= 0;
209 acpiinfo
->design_capacity_low
= 0;
212 acpiinfo
->present
= 1;
213 ptr
= jump_next_line(ptr
);
216 if (!strncmp(ptr
, "design capacity:", 16) || !strncmp(ptr
, "Design Capacity:", 16))
218 sscanf (ptr
+offset
, "%d", &(acpiinfo
->design_capacity
));
219 ptr
= jump_next_line(ptr
);
222 if (!strncmp(ptr
, "last full capacity:", 19) || !strncmp(ptr
, "Last Full Capacity:", 19))
224 sscanf (ptr
+offset
, "%d", &(acpiinfo
->last_full_capacity
));
225 ptr
= jump_next_line(ptr
);
228 if (!strncmp(ptr
, "battery technology:", 19) || !strncmp(ptr
, "Battery Technology:", 19))
233 acpiinfo
->battery_technology
= 1;
236 acpiinfo
->battery_technology
= 0;
239 ptr
= jump_next_line(ptr
);
242 if (!strncmp(ptr
, "design voltage:", 15) || !strncmp(ptr
, "Design Voltage:", 15))
244 sscanf (ptr
+offset
, "%d", &(acpiinfo
->design_voltage
));
245 ptr
= jump_next_line(ptr
);
248 if (!strncmp(ptr
, "design capacity warning:", 24) || !strncmp(ptr
, "Design Capacity Warning:", 24))
250 sscanf (ptr
+offset
, "%d", &(acpiinfo
->design_capacity_warning
));
251 ptr
= jump_next_line(ptr
);
254 if (!strncmp(ptr
, "design capacity low:", 20) || !strncmp(ptr
, "Design Capacity Low:", 20))
256 sscanf (ptr
+offset
, "%d", &(acpiinfo
->design_capacity_low
));
257 if (!count
) return; /* we did read all stuff in just one passage! */
258 ptr
= jump_next_line(ptr
);
262 ptr
= jump_next_line(ptr
);
268 void read_acpi_state (ACPIstate
*acpistate
, ACPIinfo
*acpiinfo
, int battery
)
274 if (battery
> MAXBATT
) return;
275 if (!(fp
= fopen (batteries
[battery
], "r"))) return;
277 fread_unlocked (buf
, 512, 1, fp
);
282 static int count
= 0;
284 if (!strncmp(ptr
+1, "resent:", 7))
286 if (ptr
[offset
] != 'y')
288 acpistate
->present
= 0;
289 acpistate
->state
= UNKNOW
;
290 acpistate
->prate
= 0;
291 acpistate
->rcapacity
= 0;
292 acpistate
->pvoltage
= 0;
293 acpistate
->rtime
= 0;
294 acpistate
->percentage
= 0;
298 acpistate
->present
= 1;
299 ptr
= jump_next_line(ptr
);
302 if (!strncmp(ptr
, "capacity state:", 15))
304 /* nothing to do here... */
305 ptr
= jump_next_line(ptr
);
308 if (!strncmp(ptr
, "charging state:", 15) || !strncmp(ptr
, "State:", 6))
313 acpistate
->state
= 1;
317 if (*(ptr
+ 33) == '/') acpistate
->state
= 0;
318 if (!strncmp(ptr
+offset
, "charged", 7))
319 acpistate
->state
= 1;
321 acpistate
->state
= 2;
325 acpistate
->state
= 3;
328 ptr
= jump_next_line(ptr
);
331 if (!strncmp(ptr
, "present rate:", 13) || !strncmp(ptr
, "Present Rate:", 13))
333 sscanf (ptr
+offset
, "%d", &(acpistate
->prate
));
334 /* if something wrong */
335 if (acpistate
->prate
<= 0) acpistate
->prate
= 0;
336 ptr
= jump_next_line(ptr
);
339 if (!strncmp(ptr
, "remaining capacity:", 19) || !strncmp(ptr
, "Remaining Capacity:", 19))
341 sscanf (ptr
+offset
, "%d", &(acpistate
->rcapacity
));
342 acpistate
->percentage
= (float) ((float) acpistate
->rcapacity
/ (float) acpiinfo
->last_full_capacity
) * 100;
343 ptr
= jump_next_line(ptr
);
346 if (!strncmp(ptr
, "present voltage:", 16) || !strncmp(ptr
, "Battery Voltage:", 16))
348 sscanf (ptr
+offset
, "%d", &(acpistate
->pvoltage
));
349 if (!count
) break; /* we did read all stuff in just one passage! */
350 ptr
= jump_next_line(ptr
);
354 ptr
= jump_next_line(ptr
);
358 /* time remaining in minutes */
359 if (!acpistate
->prate
) return;
360 if (acpistate
->state
== 2) /* charging */
361 acpistate
->rtime
= ((float) ((float) (acpiinfo
->last_full_capacity
- acpistate
->rcapacity
) / (float) acpistate
->prate
)) * 60;
362 else /* discharging */
363 acpistate
->rtime
= ((float) ((float) acpistate
->rcapacity
/ (float) acpistate
->prate
)) * 60;
364 if (acpistate
->rtime
<= 0) acpistate
->rtime
= 0;
367 char *find_temperature_proc_file(void)
370 char *basedir
= "/proc/acpi/thermal_zone/";
371 struct dirent
*entry
;
373 dir
= opendir(basedir
);
374 if (!dir
) return NULL
;
376 while ((entry
= readdir(dir
)))
379 if (!strcmp(entry
->d_name
, "." )) continue;
380 if (!strcmp(entry
->d_name
, "..")) continue;
381 temp
= StrApp((char**)NULL
, basedir
, entry
->d_name
, "/temperature", (char*)NULL
);
382 if (!access(temp
, R_OK
))
394 void acpi_get_temperature(int *temperature
, int *temp_is_celsius
)
398 static int searched
= 0;
399 static char *file
= NULL
;
402 (*temperature
) = PM_Error
;
403 (*temp_is_celsius
) = PM_Error
;
407 file
= find_temperature_proc_file();
411 if (!(fp
=fopen(file
, "r"))) return;
412 if (!fgets(buf
, 512, fp
))
419 if (sscanf(buf
, "%*s%d%1s", &temp
, unit
) != 2) return;
421 (*temperature
) = temp
;
422 if (*unit
== 'C') (*temp_is_celsius
) = 1;
423 else (*temp_is_celsius
) = 0;
426 int get_fan_info(void)
428 struct dirent
*entry
;
429 char *basedir
= "/proc/acpi/fan";
433 dir
= opendir(basedir
);
435 while ((entry
= readdir(dir
)))
438 if (!strcmp(entry
->d_name
, "." )) continue;
439 if (!strcmp(entry
->d_name
, "..")) continue;
440 temp
= StrApp((char**)NULL
, basedir
, "/", entry
->d_name
, "/state", (char*)NULL
);
441 if (!access(temp
, R_OK
))
443 if (n_fans
== MAXFANS
)
445 fprintf(stderr
, "acpi_lib: found more fans, but wmpower can handle only %d.\n", MAXFANS
);
449 strncpy(fans
[n_fans
], temp
, 127);
450 fans
[n_fans
][127] = '\0';
452 fprintf(stderr
, "acpi_lib: found fan info at '%s'\n", temp
);
454 else fprintf(stderr
, "acpi_lib: cannot access fan info at '%s'\n", temp
);
458 fprintf(stderr
, "acpi_lib: %d fan(s) found...\n", n_fans
);
463 /* return number of fans running */
464 int acpi_get_fan_status(void)
466 static int n_fans
= -1;
467 int running_fans
= 0;
470 if (n_fans
== -1) n_fans
= get_fan_info();
471 if (!n_fans
) return PM_Error
;
473 for (i
=0; i
<n_fans
; i
++)
476 FILE *fp
= fopen(fans
[i
], "r");
479 if (!fp
) return PM_Error
;
480 if (!fgets(buf
, 512, fp
)) ptr
= NULL
;
482 if (!ptr
) return PM_Error
;
483 if (ptr
[offset
] == 'n') running_fans
++;