1 /***************************************************************************
2 power_management.c - description
5 copyright : (C) 2003-2005 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 ***************************************************************************/
33 #include "lib_utils.h"
34 #include "power_management.h"
37 #include "toshiba_lib.h"
39 #include "compal_lib.h"
42 /* what kind of machine is running us? */
47 int machine
= UNKNOWN
;
49 int fast_charge_mode
=0;
50 int use_toshiba_hardware
=1;
53 int battery_percentage
;
58 /* Battery to monitor */
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 */
81 /* is this a compal laptop? */
82 if (machine_is_compal())
85 fprintf(stderr
, "detected Compal laptop, %s\n", compal_model
);
88 /* is this a dell laptop? */
89 if (machine_is_dell())
92 fprintf(stderr
, "detected DELL laptop\n");
95 /* Is this a Toshiba Laptop? */
96 if (machine_is_toshiba(&use_toshiba_hardware
))
99 fprintf(stderr
, "detected TOSHIBA laptop, %s\n", toshiba_model
);
100 if (!use_toshiba_hardware
) fprintf(stderr
, "direct access to TOSHIBA hardware disabled\n");
106 /* Does this system support CPU frequency scaling? */
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? */
125 fprintf(stderr
, "Detected ACPI subsystem\n");
129 /* Is this an APM system? */
133 fprintf(stderr
, "detected APM subsystem\n");
136 fprintf(stderr
, "You must use ACPI to monitor any battery\n");
137 fprintf(stderr
, "other than the first one. Cannot continue.\n");
143 fprintf(stderr
, "No power management subsystem detected\n");
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
);
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");
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;
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);
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();
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
;
252 (*temperature
) = result
;
253 (*temp_is_celsius
) = 1;
257 /* for Dell laptops... */
260 int result
= dell_get_temperature();
261 if (result
== PM_Error
)
263 (*temperature
) = PM_Error
;
264 (*temp_is_celsius
) = PM_Error
;
267 (*temperature
) = result
;
268 (*temp_is_celsius
) = 1;
272 /* No special hardware... */
273 if (pm_type
== PM_ACPI
)
275 acpi_get_temperature(temperature
, temp_is_celsius
);
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;
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");
299 /* Set CPU governor to 'performance' (or whatever our master chose when online) */
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
);
314 if (use_toshiba_hardware
&& (pm_type
!= PM_ACPI
)) toshiba_set_fan_status(1);
317 if (pm_type
== PM_ACPI
)
319 /* Set generic ACPI features here... */
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");
331 /* Set CPU governor to 'ondemand' (or whatever our master chose when offline) */
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
);
346 if (use_toshiba_hardware
&& (pm_type
!= PM_ACPI
)) toshiba_set_fan_status(0);
349 if (pm_type
== PM_ACPI
)
351 /* Set generic ACPI features here... */
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");
380 if (toggle
&& !ac_on_line
)
382 fprintf(stderr
, "Fast charge mode while on battery? I think not ;-)\n");
385 if (toggle
&& (battery_percentage
== 100))
387 fprintf(stderr
, "Battery is already at maximum capacity: fast charging not enabled\n");
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");
396 internal_set_pm_features(ac_on_line
);
402 fprintf(stderr
, "enabling fast charge mode\n");
403 internal_set_pm_features(0);
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");
455 if (!fp
) return IS_OTHER
;
456 if (!fgets(buf
, 512, fp
))
463 if (strstr(buf
, "2.6.")) return IS_2_6
;
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
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
);
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))))
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
;
507 prev_time
= curr_time
;
509 /* Seconds passed since we were initialized */
510 elapsed_time
= curr_time
- first_time
;
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
;
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;