Remove trailing whitespace.
[dockapps.git] / wmpower / src / power_management / power_management.c
blobbbec8dd9514330974da69ee09955a7c9bbdb9cca
1 /***************************************************************************
2 power_management.c - description
3 -------------------
4 begin : Feb 10 2003
5 copyright : (C) 2003-2005 by Noberasco Michele
6 e-mail : 2001s098@educ.disi.unige.it
7 ***************************************************************************/
9 /***************************************************************************
10 * *
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. *
15 * *
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. *
20 * *
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. *
25 * *
26 ***************************************************************************/
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
33 #include "lib_utils.h"
34 #include "power_management.h"
35 #include "libacpi.h"
36 #include "libapm.h"
37 #include "toshiba_lib.h"
38 #include "dell_lib.h"
39 #include "compal_lib.h"
40 #include "cpufreq.h"
42 /* what kind of machine is running us? */
43 #define UNKNOWN 0
44 #define TOSHIBA 1
45 #define DELL 2
46 #define COMPAL 3
47 int machine = UNKNOWN;
49 int fast_charge_mode=0;
50 int use_toshiba_hardware=1;
51 int pm_type=PM_Error;
52 int ac_on_line;
53 int battery_percentage;
54 int battery_present;
55 int use_noflushd=1;
56 int use_cpufreq=1;
58 /* Battery to monitor */
59 int Battery;
61 int get_fan_status();
62 void get_temperature(int *temperature, int *temp_is_celsius);
63 int fast_battery_charge(int toggle);
64 int calculate_battery_time(int battery_percentage, int ac_on_line);
65 kernel_versions Get_Kernel_version(void);
68 int pm_support(int use_this_battery)
70 Battery = use_this_battery;
72 if (!use_noflushd) fprintf(stderr, "use of noflushd is disabled\n");
73 if (!use_cpufreq) fprintf(stderr, "CPU frequency scaling disabled\n");
75 /* What kernel version are we running in? */
76 kernel_version = Get_Kernel_version();
78 /* check for specific hardware */
79 while (1)
81 /* is this a compal laptop? */
82 if (machine_is_compal())
84 machine = COMPAL;
85 fprintf(stderr, "detected Compal laptop, %s\n", compal_model);
86 break;
88 /* is this a dell laptop? */
89 if (machine_is_dell())
91 machine = DELL;
92 fprintf(stderr, "detected DELL laptop\n");
93 break;
95 /* Is this a Toshiba Laptop? */
96 if (machine_is_toshiba(&use_toshiba_hardware))
98 machine = TOSHIBA;
99 fprintf(stderr, "detected TOSHIBA laptop, %s\n", toshiba_model);
100 if (!use_toshiba_hardware) fprintf(stderr, "direct access to TOSHIBA hardware disabled\n");
101 break;
103 break;
106 /* Does this system support CPU frequency scaling? */
107 if (use_cpufreq)
109 use_cpufreq = check_cpufreq();
110 if (use_cpufreq) fprintf(stderr, "CPU frequency scaling available\n");
111 else fprintf(stderr, "CPU frequency scaling NOT available\n");
113 /* Set default governors if we were supplied none */
114 if (!cpufreq_offline_governor)
115 cpufreq_offline_governor = CPUFREQ_GOV_ONDEMAND;
117 if (!cpufreq_online_governor)
118 cpufreq_online_governor = CPUFREQ_GOV_PERFORMANCE;
121 /* Is this an acpi system? */
122 if (check_acpi())
124 pm_type= PM_ACPI;
125 fprintf(stderr, "Detected ACPI subsystem\n");
126 return 1;
129 /* Is this an APM system? */
130 if (apm_exists())
132 pm_type= PM_APM;
133 fprintf(stderr, "detected APM subsystem\n");
134 if (Battery != 1)
136 fprintf(stderr, "You must use ACPI to monitor any battery\n");
137 fprintf(stderr, "other than the first one. Cannot continue.\n");
138 exit(1);
140 return 1;
143 fprintf(stderr, "No power management subsystem detected\n");
144 return 0;
147 void get_power_status(pm_status *power_status)
149 /* Is this an ACPI system? */
150 if (pm_type == PM_ACPI)
152 static ACPIinfo acpiinfo;
153 static ACADstate acadstate;
154 static ACPIstate acpistate;
156 read_acpi_info(&acpiinfo, Battery - 1);
157 read_acpi_state(&acpistate, &acpiinfo, Battery - 1);
158 read_acad_state(&acadstate);
160 /* Check if we are on ac power */
161 ac_on_line = power_status->ac_on_line = acadstate.state;
163 /* Check to see if we are charging. */
164 if (acpistate.state == CHARGING) power_status->battery_charging=1;
165 else power_status->battery_charging=0;
167 /* Check battery time and percentage */
168 power_status->battery_time = acpistate.rtime;
169 power_status->battery_percentage = acpistate.percentage;
170 if (power_status->battery_percentage > 100) power_status->battery_percentage = 100;
171 battery_percentage = power_status->battery_percentage;
173 /* Check if battery is plugged in */
174 battery_present = power_status->battery_present = acpistate.present;
176 /* Get temperature and fan status */
177 power_status->fan_status=get_fan_status();
178 get_temperature(&(power_status->temperature), &(power_status->temp_is_celsius));
180 if (fast_charge_mode && (power_status->battery_percentage == 100)) fast_battery_charge(0);
182 /* Let's see wether we failed to get battery time */
183 if (battery_present && (battery_percentage < 100) && (power_status->battery_time <= 0))
185 /* OK, we failed, we calculate the value ourselves */
186 power_status->battery_time = calculate_battery_time(battery_percentage, ac_on_line);
189 return;
192 /* Is this an APM system? */
193 if (pm_type == PM_APM)
195 struct_apm_data apm_data;
197 if (!apm_read(&apm_data))
199 fprintf(stderr, "Could not read APM info!\n");
200 return;
203 ac_on_line = power_status->ac_on_line = apm_data.ac_line_status;
204 if ( apm_data.battery_percentage == -1)
206 battery_present = power_status->battery_present = 0;
207 battery_percentage = power_status->battery_percentage = 0;
209 else
211 battery_present = power_status->battery_present = 1;
212 power_status->battery_percentage = apm_data.battery_percentage;
213 if (power_status->battery_percentage > 100) power_status->battery_percentage = 100;
214 battery_percentage = power_status->battery_percentage;
216 if ( (int)(apm_data.battery_status) == 3)
217 power_status->battery_charging=1;
218 else power_status->battery_charging=0;
219 power_status->battery_time = (apm_data.using_minutes) ? apm_data.battery_time : apm_data.battery_time / 60;
220 power_status->fan_status=get_fan_status();
221 get_temperature(&(power_status->temperature), &(power_status->temp_is_celsius));
223 if (fast_charge_mode && (power_status->battery_percentage == 100)) fast_battery_charge(0);
225 return;
229 int get_fan_status(void)
231 if (machine == COMPAL) return compal_get_fan_status();
232 if (machine == DELL) return dell_get_fan_status();
233 if (machine == TOSHIBA) return toshiba_get_fan_status(use_toshiba_hardware);
234 if (pm_type == PM_ACPI) return acpi_get_fan_status();
236 return PM_Error;
240 void get_temperature(int *temperature, int *temp_is_celsius)
242 /* for Compal laptops... */
243 if (machine == COMPAL)
245 int result = compal_get_temperature();
246 if (result == PM_Error)
248 (*temperature) = PM_Error;
249 (*temp_is_celsius) = PM_Error;
250 return;
252 (*temperature) = result;
253 (*temp_is_celsius) = 1;
254 return;
257 /* for Dell laptops... */
258 if (machine == DELL)
260 int result = dell_get_temperature();
261 if (result == PM_Error)
263 (*temperature) = PM_Error;
264 (*temp_is_celsius) = PM_Error;
265 return;
267 (*temperature) = result;
268 (*temp_is_celsius) = 1;
269 return;
272 /* No special hardware... */
273 if (pm_type == PM_ACPI)
275 acpi_get_temperature(temperature, temp_is_celsius);
276 return;
279 /* No ACPI */
280 (*temperature) = PM_Error;
281 (*temp_is_celsius) = PM_Error;
285 void internal_set_pm_features(int ac_status)
287 static int noflushd = -1;
289 if (fast_charge_mode) ac_status=0;
290 if (ac_status)
291 { /* we are on AC power */
292 /* Stop noflushd damon (disable HD spindown) */
293 if (use_noflushd && noflushd)
295 system("/etc/init.d/noflushd stop >/dev/null 2>/dev/null");
296 noflushd = 0;
299 /* Set CPU governor to 'performance' (or whatever our master chose when online) */
300 if (use_cpufreq)
301 if (!cpufreq_set_governor(cpufreq_online_governor))
302 fprintf(stderr, "failed setting '%s' CPUfreq governor!\n", cpufreq_online_governor);
304 if (machine == COMPAL)
306 /* Set LCD to maximum brightness */
307 compal_set_lcd_brightness(COMPAL_LCD_MAX);
309 if (machine == TOSHIBA)
311 /* Set LCD to maximum brightness */
312 toshiba_set_lcd_brightness(TOSHIBA_LCD_MAX, use_toshiba_hardware);
313 /* Start fan */
314 if (use_toshiba_hardware && (pm_type != PM_ACPI)) toshiba_set_fan_status(1);
315 return;
317 if (pm_type == PM_ACPI)
319 /* Set generic ACPI features here... */
320 return;
323 else
324 { /* we are on battery power */
325 if (use_noflushd && (!noflushd || noflushd == -1))
327 /* Start noflushd damon (enable HD spindown) */
328 system("/etc/init.d/noflushd start >/dev/null 2>/dev/null");
329 noflushd = 1;
331 /* Set CPU governor to 'ondemand' (or whatever our master chose when offline) */
332 if (use_cpufreq)
333 if (!cpufreq_set_governor(cpufreq_offline_governor))
334 fprintf(stderr, "failed setting '%s' CPUfreq governor!\n", cpufreq_offline_governor);
336 if (machine == COMPAL)
338 /* Set LCD to minimum brightness */
339 compal_set_lcd_brightness(COMPAL_LCD_MIN);
341 if (machine == TOSHIBA)
343 /* Set LCD to minimum brightness */
344 toshiba_set_lcd_brightness(TOSHIBA_LCD_MIN, use_toshiba_hardware);
345 /* Stop fan */
346 if (use_toshiba_hardware && (pm_type != PM_ACPI)) toshiba_set_fan_status(0);
347 return;
349 if (pm_type == PM_ACPI)
351 /* Set generic ACPI features here... */
352 return;
359 void set_pm_features(void)
361 static int old_value = -1;
363 if (ac_on_line != old_value)
365 internal_set_pm_features(ac_on_line);
366 old_value = ac_on_line;
372 int fast_battery_charge(int toggle)
375 if (toggle && !battery_present)
377 fprintf(stderr, "Fast charge mode without a battery? I think not ;-)\n");
378 return 0;
380 if (toggle && !ac_on_line)
382 fprintf(stderr, "Fast charge mode while on battery? I think not ;-)\n");
383 return 0;
385 if (toggle && (battery_percentage == 100))
387 fprintf(stderr, "Battery is already at maximum capacity: fast charging not enabled\n");
388 return 0;
391 if (!toggle && fast_charge_mode)
393 if (battery_percentage == 100) fprintf(stderr, "battery at maximum capacity: ");
394 fprintf(stderr, "disabling fast charge mode\n");
395 fast_charge_mode=0;
396 internal_set_pm_features(ac_on_line);
397 return 0;
400 if (toggle)
402 fprintf(stderr, "enabling fast charge mode\n");
403 internal_set_pm_features(0);
404 fast_charge_mode=1;
405 return 1;
408 return fast_charge_mode;
412 int get_fast_battery_charge_mode(void)
414 return fast_charge_mode;
418 void set_noflushd_use(int toggle)
420 use_noflushd = toggle;
424 void set_toshiba_hardware_use(int toggle)
426 use_toshiba_hardware = toggle;
430 void set_cpufreq_use(int toggle)
432 use_cpufreq = toggle;
436 void lcdBrightness_UpOneStep()
438 if (machine == COMPAL) Compal_lcdBrightness_UpOneStep();
439 if (machine == TOSHIBA) Toshiba_lcdBrightness_UpOneStep(use_toshiba_hardware);
443 void lcdBrightness_DownOneStep()
445 if (machine == COMPAL) Compal_lcdBrightness_DownOneStep();
446 if (machine == TOSHIBA) Toshiba_lcdBrightness_DownOneStep(use_toshiba_hardware);
450 kernel_versions Get_Kernel_version(void)
452 FILE *fp = fopen("/proc/version", "r");
453 char buf[512];
455 if (!fp) return IS_OTHER;
456 if (!fgets(buf, 512, fp))
458 fclose(fp);
459 return IS_OTHER;
461 fclose(fp);
463 if (strstr(buf, "2.6.")) return IS_2_6;
464 return IS_OTHER;
467 /* Calculate estimated battery time
468 * note that the result this function returns
469 * is fairly inaccurate, and will be used only
470 * if we fail to get the value trough ACPI, APM
471 * or whatever...
473 int calculate_battery_time(int battery_percentage, int ac_on_line)
475 static int first_percentage = 0;
476 static int first_on_line = -1;
477 static time_t first_time = 0;
478 static time_t prev_time = 0;
479 time_t curr_time = time(NULL);
480 int battery_time;
481 int elapsed_time;
483 /* First time we are run, we cannot return anything meaningful;
484 * also, we have to reinitialize ourselves when our host switches
485 * to/from battery power. Plus, it is best to reinitialize our stuff
486 * when the time elapsed since our last update is significantly
487 * higher than our polling interval, because this likely means that
488 * the system has been suspended (we allow it some play -60 seconds-
489 * because -who knows- the system might be on really heavy load)...
491 if (!first_time || (first_on_line != ac_on_line) || (first_time && (curr_time-prev_time>(waittime + 60))))
493 if (!first_time)
495 fprintf(stderr, "could not read battery time!\n");
496 fprintf(stderr, "I will calculate it directly, but this is FAR from accurate..\n");
498 else fprintf(stderr, "re-initializing battery time!\n");
500 first_percentage = battery_percentage;
501 first_on_line = ac_on_line;
502 first_time = curr_time;
503 prev_time = curr_time;
504 return 0;
507 prev_time = curr_time;
509 /* Seconds passed since we were initialized */
510 elapsed_time = curr_time - first_time;
512 if (!ac_on_line)
513 { /* We calculate time left until battery drains out */
515 /* How much battery was drained in this time? */
516 int drained_battery = first_percentage - battery_percentage;
518 if (!drained_battery) return 0;
520 /* elapsed_time : drained_battery = ? time : remaining battery */
521 battery_time = battery_percentage * elapsed_time / drained_battery;
523 else
524 { /* We calculate time left until battery is fully recharged */
526 /* How much battery was gained in this time? */
527 int gained_battery = battery_percentage - first_percentage;
529 /* How much battery still to be charged? */
530 int remaining_battery = 100 - battery_percentage;
532 if (!gained_battery ) return 0;
533 if (!remaining_battery) return 0;
535 /* elapsed_time : gained_battery = ? time : battery still to be charged */
536 battery_time = remaining_battery * elapsed_time / gained_battery;
539 /* the value is in seconds, but we need it in minutes */
540 battery_time = battery_time / 60;
542 /* Don't allow it to be higher than 99 hours and 59 minutes,
543 * otherwise our GUI will not be able to handle it
545 if (battery_time > 5999) battery_time = 0;
547 return battery_time;