1
/***************************************************************************
3
* device_pm.c - Various power management related utilities that need to use
4
* HalDevice. This is not suitable for use in addons and probers.
6
* Copyright (C) 2005-2007 Richard Hughes <richard@hughsie.com>
7
* Copyright (C) 2005 Danny Kukawka <danny.kukawka@web.de>
9
* Licensed under the Academic Free License version 2.1
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 Free Software
23
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25
**************************************************************************/
37
#include "device_pm.h"
38
#include "device_store.h"
41
* device_pm_abstract_props:
42
* @d: Valid battery HalDevice
44
* Convert the buggy 'reporting' keys into 'charge_level' keys so stuff like
45
* desktop power managers do not have to deal with odd quirks.
48
device_pm_abstract_props (HalDevice *d)
50
const char *reporting_unit;
51
int reporting_current;
52
int reporting_lastfull;
54
int normalised_current;
55
int normalised_lastfull;
62
/* get all the data we know */
63
reporting_unit = hal_device_property_get_string (d,
64
"battery.reporting.unit");
65
reporting_current = hal_device_property_get_int (d,
66
"battery.reporting.current");
67
reporting_lastfull = hal_device_property_get_int (d,
68
"battery.reporting.last_full");
69
reporting_rate = hal_device_property_get_int (d,
70
"battery.reporting.rate");
72
/* ACPI gives out the special 'Ones' value for rate when it's unable
73
* to calculate the true rate. We should set the rate zero, and wait
74
* for the BIOS to stabilise. */
75
if (reporting_rate == 0xffff) {
79
/* We are converting the unknown units into mWh because of ACPI's nature
80
* of not having a standard unit. */
81
if (reporting_unit && strcmp (reporting_unit, "mAh") == 0) {
82
/* convert mAh to mWh by multiplying by voltage. due to the
83
* general wonkiness of ACPI implementations, this is a lot
84
* harder than it should have to be... */
86
design_voltage = hal_device_property_get_int (d, "battery.voltage.design");
87
voltage = hal_device_property_get_int (d, "battery.voltage.current");
89
/* Just in case we don't get design voltage information, then
90
* this will pretend that we have 1V. This degrades our
91
* ability to report accurate times on multi-battery systems
92
* but will always prevent negative charge levels and allow
93
* accurate reporting on single-battery systems. */
94
if (design_voltage <= 0)
95
design_voltage = 1000; /* mV */
97
/* If the current voltage is unknown, smaller than 50% of design voltage (fd.o #8593)
98
* or greater than design, then use design voltage. */
99
if (voltage < (design_voltage/2) || voltage > design_voltage) {
100
HAL_DEBUG (("Current voltage is unknown, smaller than 50%% or greater than design"));
101
voltage = design_voltage;
104
normalised_current = (reporting_current * voltage) / 1000;
105
normalised_lastfull = (reporting_lastfull * voltage) / 1000;
106
normalised_rate = (reporting_rate * voltage) / 1000;
108
/* handle as if mWh (which don't need conversion), which is
109
* the most common case. */
110
normalised_current = reporting_current;
111
normalised_lastfull = reporting_lastfull;
112
normalised_rate = reporting_rate;
116
* Check the normalised keys to see if positive.
118
if (normalised_current < 0)
119
normalised_current = 0;
120
if (normalised_lastfull < 0)
121
normalised_lastfull = 0;
122
if (normalised_rate < 0)
125
/* Some laptops report a rate even when not charging or discharging.
126
* If not charging and not discharging force rate to be zero. */
127
charging = hal_device_property_get_bool (d, "battery.rechargeable.is_charging");
128
discharging = hal_device_property_get_bool (d, "battery.rechargeable.is_discharging");
130
if (!charging && !discharging)
133
/* Some laptops report current charge much larger than
134
* full charge when at 100%. Clamp back down to 100%. */
135
if (normalised_current > normalised_lastfull)
136
normalised_current = normalised_lastfull;
138
hal_device_property_set_int (d, "battery.charge_level.current", normalised_current);
139
hal_device_property_set_int (d, "battery.charge_level.last_full", normalised_lastfull);
140
hal_device_property_set_int (d, "battery.charge_level.rate", normalised_rate);
144
* device_pm_calculate_percentage:
145
* @d: Valid battery HalDevice
147
* Calculate the percentage from the current levels and the last full level
148
* when the hardware has not given us a value.
151
device_pm_calculate_percentage (HalDevice *d)
157
/* default to fully charge to avoid triggering low power warnings on
158
* really broken batteries */
161
/* use the charge level compared to the last full amount */
162
current = hal_device_property_get_int (d, "battery.charge_level.current");
163
lastfull = hal_device_property_get_int (d, "battery.charge_level.last_full");
165
/* make sure we have current */
167
HAL_WARNING (("battery.charge_level.current %i, returning -1!", current));
168
} else if (lastfull <= 0) {
169
HAL_WARNING (("battery.charge_level.lastfull %i, percentage returning -1!", lastfull));
171
percentage = ((double) current / (double) lastfull) * 100;
172
/* Some bios's will report this out of range of 0..100, limit it here */
173
if (percentage > 100)
175
else if (percentage < 0)
178
hal_device_property_set_int (d, "battery.charge_level.percentage", percentage);
182
* device_pm_calculate_time:
183
* @d: Valid battery HalDevice
185
* Calculate the time from the rate and the last full level
186
* when the hardware has not given us a time value.
189
device_pm_calculate_time (HalDevice *d)
193
time = util_compute_time_remaining (
194
hal_device_get_udi (d),
195
hal_device_property_get_int (d, "battery.charge_level.rate"),
196
hal_device_property_get_int (d, "battery.charge_level.current"),
197
hal_device_property_get_int (d, "battery.charge_level.last_full"),
198
hal_device_property_get_bool (d, "battery.rechargeable.is_discharging"),
199
hal_device_property_get_bool (d, "battery.rechargeable.is_charging"),
200
hal_device_property_get_bool (d, "battery.remaining_time.calculate_per_time"));
202
/* zero time is unknown */
204
hal_device_property_set_int (d, "battery.remaining_time", time);
206
hal_device_property_remove (d, "battery.remaining_time");
210
* device_pm_remove_optional_props:
211
* @d: Valid battery HalDevice
213
* Removes all the optional hardware battery.* keys., i.e. the ones that are
214
* no longer valid when the battery cell is removed or changed.
215
* If the battery _device_ completely vanishes (e.g. in a docking bay) then
216
* the HalDevice should be completely removed from the device tree.
218
* Note: Removing a key that doesn't exist is OK.
221
device_pm_remove_optional_props (HalDevice *d)
223
hal_device_property_remove (d, "battery.is_rechargeable");
224
hal_device_property_remove (d, "battery.rechargeable.is_charging");
225
hal_device_property_remove (d, "battery.rechargeable.is_discharging");
226
hal_device_property_remove (d, "battery.vendor");
227
hal_device_property_remove (d, "battery.model");
228
hal_device_property_remove (d, "battery.serial");
229
hal_device_property_remove (d, "battery.reporting.technology");
230
hal_device_property_remove (d, "battery.technology");
231
hal_device_property_remove (d, "battery.vendor");
232
hal_device_property_remove (d, "battery.charge_level.unit");
233
hal_device_property_remove (d, "battery.charge_level.current");
234
hal_device_property_remove (d, "battery.charge_level.percentage");
235
hal_device_property_remove (d, "battery.charge_level.last_full");
236
hal_device_property_remove (d, "battery.charge_level.design");
237
hal_device_property_remove (d, "battery.charge_level.capacity_state");
238
hal_device_property_remove (d, "battery.charge_level.warning");
239
hal_device_property_remove (d, "battery.charge_level.low");
240
hal_device_property_remove (d, "battery.charge_level.granularity_1");
241
hal_device_property_remove (d, "battery.charge_level.granularity_2");
242
hal_device_property_remove (d, "battery.charge_level.rate");
243
hal_device_property_remove (d, "battery.voltage.unit");
244
hal_device_property_remove (d, "battery.voltage.design");
245
hal_device_property_remove (d, "battery.voltage.current");
246
hal_device_property_remove (d, "battery.alarm.unit");
247
hal_device_property_remove (d, "battery.alarm.design");
248
hal_device_property_remove (d, "battery.reporting.current");
249
hal_device_property_remove (d, "battery.reporting.last_full");
250
hal_device_property_remove (d, "battery.reporting.design");
251
hal_device_property_remove (d, "battery.reporting.rate");
252
hal_device_property_remove (d, "battery.reporting.warning");
253
hal_device_property_remove (d, "battery.reporting.low");
254
hal_device_property_remove (d, "battery.reporting.granularity_1");
255
hal_device_property_remove (d, "battery.reporting.granularity_2");
256
hal_device_property_remove (d, "battery.reporting.unit");
257
hal_device_property_remove (d, "battery.remaining_time");