Commit e91926e9ea9073d8ce95b74602e8c2d775f5a793
1 parent
ae4bb15290
Exists in
master
and in
7 other branches
apm_power: check I.intval for zero value, we use it as the divisor
Signed-off-by: Anton Vorontsov <cbou@mail.ru>
Showing 1 changed file with 3 additions and 0 deletions Inline Diff
drivers/power/apm_power.c
1 | /* | 1 | /* |
2 | * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> | 2 | * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> |
3 | * Copyright © 2007 Eugeny Boger <eugenyboger@dgap.mipt.ru> | 3 | * Copyright © 2007 Eugeny Boger <eugenyboger@dgap.mipt.ru> |
4 | * | 4 | * |
5 | * Author: Eugeny Boger <eugenyboger@dgap.mipt.ru> | 5 | * Author: Eugeny Boger <eugenyboger@dgap.mipt.ru> |
6 | * | 6 | * |
7 | * Use consistent with the GNU GPL is permitted, | 7 | * Use consistent with the GNU GPL is permitted, |
8 | * provided that this copyright notice is | 8 | * provided that this copyright notice is |
9 | * preserved in its entirety in all copies and derived works. | 9 | * preserved in its entirety in all copies and derived works. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/power_supply.h> | 13 | #include <linux/power_supply.h> |
14 | #include <linux/apm-emulation.h> | 14 | #include <linux/apm-emulation.h> |
15 | 15 | ||
16 | 16 | ||
17 | #define PSY_PROP(psy, prop, val) psy->get_property(psy, \ | 17 | #define PSY_PROP(psy, prop, val) psy->get_property(psy, \ |
18 | POWER_SUPPLY_PROP_##prop, val) | 18 | POWER_SUPPLY_PROP_##prop, val) |
19 | 19 | ||
20 | #define _MPSY_PROP(prop, val) main_battery->get_property(main_battery, \ | 20 | #define _MPSY_PROP(prop, val) main_battery->get_property(main_battery, \ |
21 | prop, val) | 21 | prop, val) |
22 | 22 | ||
23 | #define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val) | 23 | #define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val) |
24 | 24 | ||
25 | static DEFINE_MUTEX(apm_mutex); | 25 | static DEFINE_MUTEX(apm_mutex); |
26 | static struct power_supply *main_battery; | 26 | static struct power_supply *main_battery; |
27 | 27 | ||
28 | enum apm_source { | 28 | enum apm_source { |
29 | SOURCE_ENERGY, | 29 | SOURCE_ENERGY, |
30 | SOURCE_CHARGE, | 30 | SOURCE_CHARGE, |
31 | SOURCE_VOLTAGE, | 31 | SOURCE_VOLTAGE, |
32 | }; | 32 | }; |
33 | 33 | ||
34 | struct find_bat_param { | 34 | struct find_bat_param { |
35 | struct power_supply *main; | 35 | struct power_supply *main; |
36 | struct power_supply *bat; | 36 | struct power_supply *bat; |
37 | struct power_supply *max_charge_bat; | 37 | struct power_supply *max_charge_bat; |
38 | struct power_supply *max_energy_bat; | 38 | struct power_supply *max_energy_bat; |
39 | union power_supply_propval full; | 39 | union power_supply_propval full; |
40 | int max_charge; | 40 | int max_charge; |
41 | int max_energy; | 41 | int max_energy; |
42 | }; | 42 | }; |
43 | 43 | ||
44 | static int __find_main_battery(struct device *dev, void *data) | 44 | static int __find_main_battery(struct device *dev, void *data) |
45 | { | 45 | { |
46 | struct find_bat_param *bp = (struct find_bat_param *)data; | 46 | struct find_bat_param *bp = (struct find_bat_param *)data; |
47 | 47 | ||
48 | bp->bat = dev_get_drvdata(dev); | 48 | bp->bat = dev_get_drvdata(dev); |
49 | 49 | ||
50 | if (bp->bat->use_for_apm) { | 50 | if (bp->bat->use_for_apm) { |
51 | /* nice, we explicitly asked to report this battery. */ | 51 | /* nice, we explicitly asked to report this battery. */ |
52 | bp->main = bp->bat; | 52 | bp->main = bp->bat; |
53 | return 1; | 53 | return 1; |
54 | } | 54 | } |
55 | 55 | ||
56 | if (!PSY_PROP(bp->bat, CHARGE_FULL_DESIGN, &bp->full) || | 56 | if (!PSY_PROP(bp->bat, CHARGE_FULL_DESIGN, &bp->full) || |
57 | !PSY_PROP(bp->bat, CHARGE_FULL, &bp->full)) { | 57 | !PSY_PROP(bp->bat, CHARGE_FULL, &bp->full)) { |
58 | if (bp->full.intval > bp->max_charge) { | 58 | if (bp->full.intval > bp->max_charge) { |
59 | bp->max_charge_bat = bp->bat; | 59 | bp->max_charge_bat = bp->bat; |
60 | bp->max_charge = bp->full.intval; | 60 | bp->max_charge = bp->full.intval; |
61 | } | 61 | } |
62 | } else if (!PSY_PROP(bp->bat, ENERGY_FULL_DESIGN, &bp->full) || | 62 | } else if (!PSY_PROP(bp->bat, ENERGY_FULL_DESIGN, &bp->full) || |
63 | !PSY_PROP(bp->bat, ENERGY_FULL, &bp->full)) { | 63 | !PSY_PROP(bp->bat, ENERGY_FULL, &bp->full)) { |
64 | if (bp->full.intval > bp->max_energy) { | 64 | if (bp->full.intval > bp->max_energy) { |
65 | bp->max_energy_bat = bp->bat; | 65 | bp->max_energy_bat = bp->bat; |
66 | bp->max_energy = bp->full.intval; | 66 | bp->max_energy = bp->full.intval; |
67 | } | 67 | } |
68 | } | 68 | } |
69 | return 0; | 69 | return 0; |
70 | } | 70 | } |
71 | 71 | ||
72 | static void find_main_battery(void) | 72 | static void find_main_battery(void) |
73 | { | 73 | { |
74 | struct find_bat_param bp; | 74 | struct find_bat_param bp; |
75 | int error; | 75 | int error; |
76 | 76 | ||
77 | memset(&bp, 0, sizeof(struct find_bat_param)); | 77 | memset(&bp, 0, sizeof(struct find_bat_param)); |
78 | main_battery = NULL; | 78 | main_battery = NULL; |
79 | bp.main = main_battery; | 79 | bp.main = main_battery; |
80 | 80 | ||
81 | error = class_for_each_device(power_supply_class, &bp, | 81 | error = class_for_each_device(power_supply_class, &bp, |
82 | __find_main_battery); | 82 | __find_main_battery); |
83 | if (error) { | 83 | if (error) { |
84 | main_battery = bp.main; | 84 | main_battery = bp.main; |
85 | return; | 85 | return; |
86 | } | 86 | } |
87 | 87 | ||
88 | if ((bp.max_energy_bat && bp.max_charge_bat) && | 88 | if ((bp.max_energy_bat && bp.max_charge_bat) && |
89 | (bp.max_energy_bat != bp.max_charge_bat)) { | 89 | (bp.max_energy_bat != bp.max_charge_bat)) { |
90 | /* try guess battery with more capacity */ | 90 | /* try guess battery with more capacity */ |
91 | if (!PSY_PROP(bp.max_charge_bat, VOLTAGE_MAX_DESIGN, | 91 | if (!PSY_PROP(bp.max_charge_bat, VOLTAGE_MAX_DESIGN, |
92 | &bp.full)) { | 92 | &bp.full)) { |
93 | if (bp.max_energy > bp.max_charge * bp.full.intval) | 93 | if (bp.max_energy > bp.max_charge * bp.full.intval) |
94 | main_battery = bp.max_energy_bat; | 94 | main_battery = bp.max_energy_bat; |
95 | else | 95 | else |
96 | main_battery = bp.max_charge_bat; | 96 | main_battery = bp.max_charge_bat; |
97 | } else if (!PSY_PROP(bp.max_energy_bat, VOLTAGE_MAX_DESIGN, | 97 | } else if (!PSY_PROP(bp.max_energy_bat, VOLTAGE_MAX_DESIGN, |
98 | &bp.full)) { | 98 | &bp.full)) { |
99 | if (bp.max_charge > bp.max_energy / bp.full.intval) | 99 | if (bp.max_charge > bp.max_energy / bp.full.intval) |
100 | main_battery = bp.max_charge_bat; | 100 | main_battery = bp.max_charge_bat; |
101 | else | 101 | else |
102 | main_battery = bp.max_energy_bat; | 102 | main_battery = bp.max_energy_bat; |
103 | } else { | 103 | } else { |
104 | /* give up, choice any */ | 104 | /* give up, choice any */ |
105 | main_battery = bp.max_energy_bat; | 105 | main_battery = bp.max_energy_bat; |
106 | } | 106 | } |
107 | } else if (bp.max_charge_bat) { | 107 | } else if (bp.max_charge_bat) { |
108 | main_battery = bp.max_charge_bat; | 108 | main_battery = bp.max_charge_bat; |
109 | } else if (bp.max_energy_bat) { | 109 | } else if (bp.max_energy_bat) { |
110 | main_battery = bp.max_energy_bat; | 110 | main_battery = bp.max_energy_bat; |
111 | } else { | 111 | } else { |
112 | /* give up, try the last if any */ | 112 | /* give up, try the last if any */ |
113 | main_battery = bp.bat; | 113 | main_battery = bp.bat; |
114 | } | 114 | } |
115 | } | 115 | } |
116 | 116 | ||
117 | static int do_calculate_time(int status, enum apm_source source) | 117 | static int do_calculate_time(int status, enum apm_source source) |
118 | { | 118 | { |
119 | union power_supply_propval full; | 119 | union power_supply_propval full; |
120 | union power_supply_propval empty; | 120 | union power_supply_propval empty; |
121 | union power_supply_propval cur; | 121 | union power_supply_propval cur; |
122 | union power_supply_propval I; | 122 | union power_supply_propval I; |
123 | enum power_supply_property full_prop; | 123 | enum power_supply_property full_prop; |
124 | enum power_supply_property full_design_prop; | 124 | enum power_supply_property full_design_prop; |
125 | enum power_supply_property empty_prop; | 125 | enum power_supply_property empty_prop; |
126 | enum power_supply_property empty_design_prop; | 126 | enum power_supply_property empty_design_prop; |
127 | enum power_supply_property cur_avg_prop; | 127 | enum power_supply_property cur_avg_prop; |
128 | enum power_supply_property cur_now_prop; | 128 | enum power_supply_property cur_now_prop; |
129 | 129 | ||
130 | if (MPSY_PROP(CURRENT_AVG, &I)) { | 130 | if (MPSY_PROP(CURRENT_AVG, &I)) { |
131 | /* if battery can't report average value, use momentary */ | 131 | /* if battery can't report average value, use momentary */ |
132 | if (MPSY_PROP(CURRENT_NOW, &I)) | 132 | if (MPSY_PROP(CURRENT_NOW, &I)) |
133 | return -1; | 133 | return -1; |
134 | } | 134 | } |
135 | 135 | ||
136 | if (!I.intval) | ||
137 | return 0; | ||
138 | |||
136 | switch (source) { | 139 | switch (source) { |
137 | case SOURCE_CHARGE: | 140 | case SOURCE_CHARGE: |
138 | full_prop = POWER_SUPPLY_PROP_CHARGE_FULL; | 141 | full_prop = POWER_SUPPLY_PROP_CHARGE_FULL; |
139 | full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN; | 142 | full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN; |
140 | empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; | 143 | empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; |
141 | empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; | 144 | empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; |
142 | cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG; | 145 | cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG; |
143 | cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW; | 146 | cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW; |
144 | break; | 147 | break; |
145 | case SOURCE_ENERGY: | 148 | case SOURCE_ENERGY: |
146 | full_prop = POWER_SUPPLY_PROP_ENERGY_FULL; | 149 | full_prop = POWER_SUPPLY_PROP_ENERGY_FULL; |
147 | full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN; | 150 | full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN; |
148 | empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY; | 151 | empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY; |
149 | empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; | 152 | empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; |
150 | cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG; | 153 | cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG; |
151 | cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW; | 154 | cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW; |
152 | break; | 155 | break; |
153 | case SOURCE_VOLTAGE: | 156 | case SOURCE_VOLTAGE: |
154 | full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX; | 157 | full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX; |
155 | full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN; | 158 | full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN; |
156 | empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN; | 159 | empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN; |
157 | empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN; | 160 | empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN; |
158 | cur_avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG; | 161 | cur_avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG; |
159 | cur_now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW; | 162 | cur_now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW; |
160 | break; | 163 | break; |
161 | default: | 164 | default: |
162 | printk(KERN_ERR "Unsupported source: %d\n", source); | 165 | printk(KERN_ERR "Unsupported source: %d\n", source); |
163 | return -1; | 166 | return -1; |
164 | } | 167 | } |
165 | 168 | ||
166 | if (_MPSY_PROP(full_prop, &full)) { | 169 | if (_MPSY_PROP(full_prop, &full)) { |
167 | /* if battery can't report this property, use design value */ | 170 | /* if battery can't report this property, use design value */ |
168 | if (_MPSY_PROP(full_design_prop, &full)) | 171 | if (_MPSY_PROP(full_design_prop, &full)) |
169 | return -1; | 172 | return -1; |
170 | } | 173 | } |
171 | 174 | ||
172 | if (_MPSY_PROP(empty_prop, &empty)) { | 175 | if (_MPSY_PROP(empty_prop, &empty)) { |
173 | /* if battery can't report this property, use design value */ | 176 | /* if battery can't report this property, use design value */ |
174 | if (_MPSY_PROP(empty_design_prop, &empty)) | 177 | if (_MPSY_PROP(empty_design_prop, &empty)) |
175 | empty.intval = 0; | 178 | empty.intval = 0; |
176 | } | 179 | } |
177 | 180 | ||
178 | if (_MPSY_PROP(cur_avg_prop, &cur)) { | 181 | if (_MPSY_PROP(cur_avg_prop, &cur)) { |
179 | /* if battery can't report average value, use momentary */ | 182 | /* if battery can't report average value, use momentary */ |
180 | if (_MPSY_PROP(cur_now_prop, &cur)) | 183 | if (_MPSY_PROP(cur_now_prop, &cur)) |
181 | return -1; | 184 | return -1; |
182 | } | 185 | } |
183 | 186 | ||
184 | if (status == POWER_SUPPLY_STATUS_CHARGING) | 187 | if (status == POWER_SUPPLY_STATUS_CHARGING) |
185 | return ((cur.intval - full.intval) * 60L) / I.intval; | 188 | return ((cur.intval - full.intval) * 60L) / I.intval; |
186 | else | 189 | else |
187 | return -((cur.intval - empty.intval) * 60L) / I.intval; | 190 | return -((cur.intval - empty.intval) * 60L) / I.intval; |
188 | } | 191 | } |
189 | 192 | ||
190 | static int calculate_time(int status) | 193 | static int calculate_time(int status) |
191 | { | 194 | { |
192 | int time; | 195 | int time; |
193 | 196 | ||
194 | time = do_calculate_time(status, SOURCE_ENERGY); | 197 | time = do_calculate_time(status, SOURCE_ENERGY); |
195 | if (time != -1) | 198 | if (time != -1) |
196 | return time; | 199 | return time; |
197 | 200 | ||
198 | time = do_calculate_time(status, SOURCE_CHARGE); | 201 | time = do_calculate_time(status, SOURCE_CHARGE); |
199 | if (time != -1) | 202 | if (time != -1) |
200 | return time; | 203 | return time; |
201 | 204 | ||
202 | time = do_calculate_time(status, SOURCE_VOLTAGE); | 205 | time = do_calculate_time(status, SOURCE_VOLTAGE); |
203 | if (time != -1) | 206 | if (time != -1) |
204 | return time; | 207 | return time; |
205 | 208 | ||
206 | return -1; | 209 | return -1; |
207 | } | 210 | } |
208 | 211 | ||
209 | static int calculate_capacity(enum apm_source source) | 212 | static int calculate_capacity(enum apm_source source) |
210 | { | 213 | { |
211 | enum power_supply_property full_prop, empty_prop; | 214 | enum power_supply_property full_prop, empty_prop; |
212 | enum power_supply_property full_design_prop, empty_design_prop; | 215 | enum power_supply_property full_design_prop, empty_design_prop; |
213 | enum power_supply_property now_prop, avg_prop; | 216 | enum power_supply_property now_prop, avg_prop; |
214 | union power_supply_propval empty, full, cur; | 217 | union power_supply_propval empty, full, cur; |
215 | int ret; | 218 | int ret; |
216 | 219 | ||
217 | switch (source) { | 220 | switch (source) { |
218 | case SOURCE_CHARGE: | 221 | case SOURCE_CHARGE: |
219 | full_prop = POWER_SUPPLY_PROP_CHARGE_FULL; | 222 | full_prop = POWER_SUPPLY_PROP_CHARGE_FULL; |
220 | empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; | 223 | empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; |
221 | full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN; | 224 | full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN; |
222 | empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN; | 225 | empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN; |
223 | now_prop = POWER_SUPPLY_PROP_CHARGE_NOW; | 226 | now_prop = POWER_SUPPLY_PROP_CHARGE_NOW; |
224 | avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG; | 227 | avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG; |
225 | break; | 228 | break; |
226 | case SOURCE_ENERGY: | 229 | case SOURCE_ENERGY: |
227 | full_prop = POWER_SUPPLY_PROP_ENERGY_FULL; | 230 | full_prop = POWER_SUPPLY_PROP_ENERGY_FULL; |
228 | empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY; | 231 | empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY; |
229 | full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN; | 232 | full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN; |
230 | empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN; | 233 | empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN; |
231 | now_prop = POWER_SUPPLY_PROP_ENERGY_NOW; | 234 | now_prop = POWER_SUPPLY_PROP_ENERGY_NOW; |
232 | avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG; | 235 | avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG; |
233 | case SOURCE_VOLTAGE: | 236 | case SOURCE_VOLTAGE: |
234 | full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX; | 237 | full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX; |
235 | empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN; | 238 | empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN; |
236 | full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN; | 239 | full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN; |
237 | empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN; | 240 | empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN; |
238 | now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW; | 241 | now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW; |
239 | avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG; | 242 | avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG; |
240 | break; | 243 | break; |
241 | default: | 244 | default: |
242 | printk(KERN_ERR "Unsupported source: %d\n", source); | 245 | printk(KERN_ERR "Unsupported source: %d\n", source); |
243 | return -1; | 246 | return -1; |
244 | } | 247 | } |
245 | 248 | ||
246 | if (_MPSY_PROP(full_prop, &full)) { | 249 | if (_MPSY_PROP(full_prop, &full)) { |
247 | /* if battery can't report this property, use design value */ | 250 | /* if battery can't report this property, use design value */ |
248 | if (_MPSY_PROP(full_design_prop, &full)) | 251 | if (_MPSY_PROP(full_design_prop, &full)) |
249 | return -1; | 252 | return -1; |
250 | } | 253 | } |
251 | 254 | ||
252 | if (_MPSY_PROP(avg_prop, &cur)) { | 255 | if (_MPSY_PROP(avg_prop, &cur)) { |
253 | /* if battery can't report average value, use momentary */ | 256 | /* if battery can't report average value, use momentary */ |
254 | if (_MPSY_PROP(now_prop, &cur)) | 257 | if (_MPSY_PROP(now_prop, &cur)) |
255 | return -1; | 258 | return -1; |
256 | } | 259 | } |
257 | 260 | ||
258 | if (_MPSY_PROP(empty_prop, &empty)) { | 261 | if (_MPSY_PROP(empty_prop, &empty)) { |
259 | /* if battery can't report this property, use design value */ | 262 | /* if battery can't report this property, use design value */ |
260 | if (_MPSY_PROP(empty_design_prop, &empty)) | 263 | if (_MPSY_PROP(empty_design_prop, &empty)) |
261 | empty.intval = 0; | 264 | empty.intval = 0; |
262 | } | 265 | } |
263 | 266 | ||
264 | if (full.intval - empty.intval) | 267 | if (full.intval - empty.intval) |
265 | ret = ((cur.intval - empty.intval) * 100L) / | 268 | ret = ((cur.intval - empty.intval) * 100L) / |
266 | (full.intval - empty.intval); | 269 | (full.intval - empty.intval); |
267 | else | 270 | else |
268 | return -1; | 271 | return -1; |
269 | 272 | ||
270 | if (ret > 100) | 273 | if (ret > 100) |
271 | return 100; | 274 | return 100; |
272 | else if (ret < 0) | 275 | else if (ret < 0) |
273 | return 0; | 276 | return 0; |
274 | 277 | ||
275 | return ret; | 278 | return ret; |
276 | } | 279 | } |
277 | 280 | ||
278 | static void apm_battery_apm_get_power_status(struct apm_power_info *info) | 281 | static void apm_battery_apm_get_power_status(struct apm_power_info *info) |
279 | { | 282 | { |
280 | union power_supply_propval status; | 283 | union power_supply_propval status; |
281 | union power_supply_propval capacity, time_to_full, time_to_empty; | 284 | union power_supply_propval capacity, time_to_full, time_to_empty; |
282 | 285 | ||
283 | mutex_lock(&apm_mutex); | 286 | mutex_lock(&apm_mutex); |
284 | find_main_battery(); | 287 | find_main_battery(); |
285 | if (!main_battery) { | 288 | if (!main_battery) { |
286 | mutex_unlock(&apm_mutex); | 289 | mutex_unlock(&apm_mutex); |
287 | return; | 290 | return; |
288 | } | 291 | } |
289 | 292 | ||
290 | /* status */ | 293 | /* status */ |
291 | 294 | ||
292 | if (MPSY_PROP(STATUS, &status)) | 295 | if (MPSY_PROP(STATUS, &status)) |
293 | status.intval = POWER_SUPPLY_STATUS_UNKNOWN; | 296 | status.intval = POWER_SUPPLY_STATUS_UNKNOWN; |
294 | 297 | ||
295 | /* ac line status */ | 298 | /* ac line status */ |
296 | 299 | ||
297 | if ((status.intval == POWER_SUPPLY_STATUS_CHARGING) || | 300 | if ((status.intval == POWER_SUPPLY_STATUS_CHARGING) || |
298 | (status.intval == POWER_SUPPLY_STATUS_NOT_CHARGING) || | 301 | (status.intval == POWER_SUPPLY_STATUS_NOT_CHARGING) || |
299 | (status.intval == POWER_SUPPLY_STATUS_FULL)) | 302 | (status.intval == POWER_SUPPLY_STATUS_FULL)) |
300 | info->ac_line_status = APM_AC_ONLINE; | 303 | info->ac_line_status = APM_AC_ONLINE; |
301 | else | 304 | else |
302 | info->ac_line_status = APM_AC_OFFLINE; | 305 | info->ac_line_status = APM_AC_OFFLINE; |
303 | 306 | ||
304 | /* battery life (i.e. capacity, in percents) */ | 307 | /* battery life (i.e. capacity, in percents) */ |
305 | 308 | ||
306 | if (MPSY_PROP(CAPACITY, &capacity) == 0) { | 309 | if (MPSY_PROP(CAPACITY, &capacity) == 0) { |
307 | info->battery_life = capacity.intval; | 310 | info->battery_life = capacity.intval; |
308 | } else { | 311 | } else { |
309 | /* try calculate using energy */ | 312 | /* try calculate using energy */ |
310 | info->battery_life = calculate_capacity(SOURCE_ENERGY); | 313 | info->battery_life = calculate_capacity(SOURCE_ENERGY); |
311 | /* if failed try calculate using charge instead */ | 314 | /* if failed try calculate using charge instead */ |
312 | if (info->battery_life == -1) | 315 | if (info->battery_life == -1) |
313 | info->battery_life = calculate_capacity(SOURCE_CHARGE); | 316 | info->battery_life = calculate_capacity(SOURCE_CHARGE); |
314 | if (info->battery_life == -1) | 317 | if (info->battery_life == -1) |
315 | info->battery_life = calculate_capacity(SOURCE_VOLTAGE); | 318 | info->battery_life = calculate_capacity(SOURCE_VOLTAGE); |
316 | } | 319 | } |
317 | 320 | ||
318 | /* charging status */ | 321 | /* charging status */ |
319 | 322 | ||
320 | if (status.intval == POWER_SUPPLY_STATUS_CHARGING) { | 323 | if (status.intval == POWER_SUPPLY_STATUS_CHARGING) { |
321 | info->battery_status = APM_BATTERY_STATUS_CHARGING; | 324 | info->battery_status = APM_BATTERY_STATUS_CHARGING; |
322 | } else { | 325 | } else { |
323 | if (info->battery_life > 50) | 326 | if (info->battery_life > 50) |
324 | info->battery_status = APM_BATTERY_STATUS_HIGH; | 327 | info->battery_status = APM_BATTERY_STATUS_HIGH; |
325 | else if (info->battery_life > 5) | 328 | else if (info->battery_life > 5) |
326 | info->battery_status = APM_BATTERY_STATUS_LOW; | 329 | info->battery_status = APM_BATTERY_STATUS_LOW; |
327 | else | 330 | else |
328 | info->battery_status = APM_BATTERY_STATUS_CRITICAL; | 331 | info->battery_status = APM_BATTERY_STATUS_CRITICAL; |
329 | } | 332 | } |
330 | info->battery_flag = info->battery_status; | 333 | info->battery_flag = info->battery_status; |
331 | 334 | ||
332 | /* time */ | 335 | /* time */ |
333 | 336 | ||
334 | info->units = APM_UNITS_MINS; | 337 | info->units = APM_UNITS_MINS; |
335 | 338 | ||
336 | if (status.intval == POWER_SUPPLY_STATUS_CHARGING) { | 339 | if (status.intval == POWER_SUPPLY_STATUS_CHARGING) { |
337 | if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) || | 340 | if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) || |
338 | !MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) | 341 | !MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) |
339 | info->time = time_to_full.intval / 60; | 342 | info->time = time_to_full.intval / 60; |
340 | else | 343 | else |
341 | info->time = calculate_time(status.intval); | 344 | info->time = calculate_time(status.intval); |
342 | } else { | 345 | } else { |
343 | if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) || | 346 | if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) || |
344 | !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) | 347 | !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) |
345 | info->time = time_to_empty.intval / 60; | 348 | info->time = time_to_empty.intval / 60; |
346 | else | 349 | else |
347 | info->time = calculate_time(status.intval); | 350 | info->time = calculate_time(status.intval); |
348 | } | 351 | } |
349 | 352 | ||
350 | mutex_unlock(&apm_mutex); | 353 | mutex_unlock(&apm_mutex); |
351 | } | 354 | } |
352 | 355 | ||
353 | static int __init apm_battery_init(void) | 356 | static int __init apm_battery_init(void) |
354 | { | 357 | { |
355 | printk(KERN_INFO "APM Battery Driver\n"); | 358 | printk(KERN_INFO "APM Battery Driver\n"); |
356 | 359 | ||
357 | apm_get_power_status = apm_battery_apm_get_power_status; | 360 | apm_get_power_status = apm_battery_apm_get_power_status; |
358 | return 0; | 361 | return 0; |
359 | } | 362 | } |
360 | 363 | ||
361 | static void __exit apm_battery_exit(void) | 364 | static void __exit apm_battery_exit(void) |
362 | { | 365 | { |
363 | apm_get_power_status = NULL; | 366 | apm_get_power_status = NULL; |
364 | } | 367 | } |
365 | 368 | ||
366 | module_init(apm_battery_init); | 369 | module_init(apm_battery_init); |
367 | module_exit(apm_battery_exit); | 370 | module_exit(apm_battery_exit); |
368 | 371 | ||
369 | MODULE_AUTHOR("Eugeny Boger <eugenyboger@dgap.mipt.ru>"); | 372 | MODULE_AUTHOR("Eugeny Boger <eugenyboger@dgap.mipt.ru>"); |
370 | MODULE_DESCRIPTION("APM emulation driver for battery monitoring class"); | 373 | MODULE_DESCRIPTION("APM emulation driver for battery monitoring class"); |
371 | MODULE_LICENSE("GPL"); | 374 | MODULE_LICENSE("GPL"); |
372 | 375 |