diff options
Diffstat (limited to 'drivers/acpi/battery.c')
-rw-r--r-- | drivers/acpi/battery.c | 613 |
1 files changed, 441 insertions, 172 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index df04f87dd491..f3b0024e5760 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c | |||
@@ -52,12 +52,24 @@ | |||
52 | #define ACPI_BATTERY_UNITS_AMPS "mA" | 52 | #define ACPI_BATTERY_UNITS_AMPS "mA" |
53 | 53 | ||
54 | #define _COMPONENT ACPI_BATTERY_COMPONENT | 54 | #define _COMPONENT ACPI_BATTERY_COMPONENT |
55 | |||
56 | #define ACPI_BATTERY_UPDATE_TIME 0 | ||
57 | |||
58 | #define ACPI_BATTERY_NONE_UPDATE 0 | ||
59 | #define ACPI_BATTERY_EASY_UPDATE 1 | ||
60 | #define ACPI_BATTERY_INIT_UPDATE 2 | ||
61 | |||
55 | ACPI_MODULE_NAME("battery"); | 62 | ACPI_MODULE_NAME("battery"); |
56 | 63 | ||
57 | MODULE_AUTHOR("Paul Diefenbaugh"); | 64 | MODULE_AUTHOR("Paul Diefenbaugh"); |
58 | MODULE_DESCRIPTION("ACPI Battery Driver"); | 65 | MODULE_DESCRIPTION("ACPI Battery Driver"); |
59 | MODULE_LICENSE("GPL"); | 66 | MODULE_LICENSE("GPL"); |
60 | 67 | ||
68 | static unsigned int update_time = ACPI_BATTERY_UPDATE_TIME; | ||
69 | |||
70 | /* 0 - every time, > 0 - by update_time */ | ||
71 | module_param(update_time, uint, 0644); | ||
72 | |||
61 | extern struct proc_dir_entry *acpi_lock_battery_dir(void); | 73 | extern struct proc_dir_entry *acpi_lock_battery_dir(void); |
62 | extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); | 74 | extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); |
63 | 75 | ||
@@ -100,32 +112,117 @@ struct acpi_battery_info { | |||
100 | }; | 112 | }; |
101 | 113 | ||
102 | struct acpi_battery_flags { | 114 | struct acpi_battery_flags { |
103 | u8 present:1; /* Bay occupied? */ | 115 | u8 battery_present_prev; |
104 | u8 power_unit:1; /* 0=watts, 1=apms */ | 116 | u8 alarm_present; |
105 | u8 alarm:1; /* _BTP present? */ | 117 | u8 init_update; |
106 | u8 reserved:5; | 118 | u8 info_update; |
107 | }; | 119 | u8 state_update; |
108 | 120 | u8 alarm_update; | |
109 | struct acpi_battery_trips { | 121 | u8 power_unit; |
110 | unsigned long warning; | ||
111 | unsigned long low; | ||
112 | }; | 122 | }; |
113 | 123 | ||
114 | struct acpi_battery { | 124 | struct acpi_battery { |
125 | struct mutex mutex; | ||
115 | struct acpi_device * device; | 126 | struct acpi_device * device; |
116 | struct acpi_battery_flags flags; | 127 | struct acpi_battery_flags flags; |
117 | struct acpi_battery_trips trips; | 128 | struct acpi_buffer bif_data; |
129 | struct acpi_buffer bst_data; | ||
118 | unsigned long alarm; | 130 | unsigned long alarm; |
119 | struct acpi_battery_info *info; | 131 | unsigned long info_update_time; |
132 | unsigned long state_update_time; | ||
133 | unsigned long alarm_update_time; | ||
120 | }; | 134 | }; |
121 | 135 | ||
136 | #define acpi_battery_present(battery) battery->device->status.battery_present | ||
137 | #define acpi_battery_present_prev(battery) battery->flags.battery_present_prev | ||
138 | #define acpi_battery_alarm_present(battery) battery->flags.alarm_present | ||
139 | #define acpi_battery_init_update_flag(battery) battery->flags.init_update | ||
140 | #define acpi_battery_info_update_flag(battery) battery->flags.info_update | ||
141 | #define acpi_battery_state_update_flag(battery) battery->flags.state_update | ||
142 | #define acpi_battery_alarm_update_flag(battery) battery->flags.alarm_update | ||
143 | #define acpi_battery_power_units(battery) battery->flags.power_unit ? \ | ||
144 | ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS | ||
145 | #define acpi_battery_handle(battery) battery->device->handle | ||
146 | #define acpi_battery_inserted(battery) (!acpi_battery_present_prev(battery) & acpi_battery_present(battery)) | ||
147 | #define acpi_battery_removed(battery) (acpi_battery_present_prev(battery) & !acpi_battery_present(battery)) | ||
148 | #define acpi_battery_bid(battery) acpi_device_bid(battery->device) | ||
149 | #define acpi_battery_status_str(battery) acpi_battery_present(battery) ? "present" : "absent" | ||
150 | |||
122 | /* -------------------------------------------------------------------------- | 151 | /* -------------------------------------------------------------------------- |
123 | Battery Management | 152 | Battery Management |
124 | -------------------------------------------------------------------------- */ | 153 | -------------------------------------------------------------------------- */ |
125 | 154 | ||
126 | static int | 155 | static void acpi_battery_mutex_lock(struct acpi_battery *battery) |
127 | acpi_battery_get_info(struct acpi_battery *battery, | 156 | { |
128 | struct acpi_battery_info **bif) | 157 | mutex_lock(&battery->mutex); |
158 | } | ||
159 | |||
160 | static void acpi_battery_mutex_unlock(struct acpi_battery *battery) | ||
161 | { | ||
162 | mutex_unlock(&battery->mutex); | ||
163 | } | ||
164 | |||
165 | static void acpi_battery_check_result(struct acpi_battery *battery, int result) | ||
166 | { | ||
167 | if (!battery) | ||
168 | return; | ||
169 | |||
170 | if (result) { | ||
171 | acpi_battery_init_update_flag(battery) = 1; | ||
172 | } | ||
173 | } | ||
174 | |||
175 | static int acpi_battery_extract_package(struct acpi_battery *battery, | ||
176 | union acpi_object *package, | ||
177 | struct acpi_buffer *format, | ||
178 | struct acpi_buffer *data, | ||
179 | char *package_name) | ||
180 | { | ||
181 | acpi_status status = AE_OK; | ||
182 | struct acpi_buffer data_null = { 0, NULL }; | ||
183 | |||
184 | status = acpi_extract_package(package, format, &data_null); | ||
185 | if (status != AE_BUFFER_OVERFLOW) { | ||
186 | ACPI_EXCEPTION((AE_INFO, status, "Extracting size %s", | ||
187 | package_name)); | ||
188 | return -ENODEV; | ||
189 | } | ||
190 | |||
191 | if (data_null.length != data->length) { | ||
192 | if (data->pointer) { | ||
193 | kfree(data->pointer); | ||
194 | } | ||
195 | data->pointer = kzalloc(data_null.length, GFP_KERNEL); | ||
196 | if (!data->pointer) { | ||
197 | ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "kzalloc()")); | ||
198 | return -ENOMEM; | ||
199 | } | ||
200 | data->length = data_null.length; | ||
201 | } | ||
202 | |||
203 | status = acpi_extract_package(package, format, data); | ||
204 | if (ACPI_FAILURE(status)) { | ||
205 | ACPI_EXCEPTION((AE_INFO, status, "Extracting %s", | ||
206 | package_name)); | ||
207 | return -ENODEV; | ||
208 | } | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static int acpi_battery_get_status(struct acpi_battery *battery) | ||
214 | { | ||
215 | int result = 0; | ||
216 | |||
217 | result = acpi_bus_get_status(battery->device); | ||
218 | if (result) { | ||
219 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA")); | ||
220 | return -ENODEV; | ||
221 | } | ||
222 | return result; | ||
223 | } | ||
224 | |||
225 | static int acpi_battery_get_info(struct acpi_battery *battery) | ||
129 | { | 226 | { |
130 | int result = 0; | 227 | int result = 0; |
131 | acpi_status status = 0; | 228 | acpi_status status = 0; |
@@ -133,16 +230,18 @@ acpi_battery_get_info(struct acpi_battery *battery, | |||
133 | struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF), | 230 | struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF), |
134 | ACPI_BATTERY_FORMAT_BIF | 231 | ACPI_BATTERY_FORMAT_BIF |
135 | }; | 232 | }; |
136 | struct acpi_buffer data = { 0, NULL }; | ||
137 | union acpi_object *package = NULL; | 233 | union acpi_object *package = NULL; |
234 | struct acpi_buffer *data = NULL; | ||
235 | struct acpi_battery_info *bif = NULL; | ||
138 | 236 | ||
237 | battery->info_update_time = get_seconds(); | ||
139 | 238 | ||
140 | if (!battery || !bif) | 239 | if (!acpi_battery_present(battery)) |
141 | return -EINVAL; | 240 | return 0; |
142 | 241 | ||
143 | /* Evalute _BIF */ | 242 | /* Evalute _BIF */ |
144 | 243 | ||
145 | status = acpi_evaluate_object(battery->device->handle, "_BIF", NULL, &buffer); | 244 | status = acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL, &buffer); |
146 | if (ACPI_FAILURE(status)) { | 245 | if (ACPI_FAILURE(status)) { |
147 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF")); | 246 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF")); |
148 | return -ENODEV; | 247 | return -ENODEV; |
@@ -150,41 +249,29 @@ acpi_battery_get_info(struct acpi_battery *battery, | |||
150 | 249 | ||
151 | package = buffer.pointer; | 250 | package = buffer.pointer; |
152 | 251 | ||
252 | data = &battery->bif_data; | ||
253 | |||
153 | /* Extract Package Data */ | 254 | /* Extract Package Data */ |
154 | 255 | ||
155 | status = acpi_extract_package(package, &format, &data); | 256 | result = acpi_battery_extract_package(battery, package, &format, data, "_BIF"); |
156 | if (status != AE_BUFFER_OVERFLOW) { | 257 | if (result) |
157 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF")); | ||
158 | result = -ENODEV; | ||
159 | goto end; | 258 | goto end; |
160 | } | ||
161 | 259 | ||
162 | data.pointer = kzalloc(data.length, GFP_KERNEL); | 260 | end: |
163 | if (!data.pointer) { | ||
164 | result = -ENOMEM; | ||
165 | goto end; | ||
166 | } | ||
167 | 261 | ||
168 | status = acpi_extract_package(package, &format, &data); | 262 | if (buffer.pointer) { |
169 | if (ACPI_FAILURE(status)) { | 263 | kfree(buffer.pointer); |
170 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF")); | ||
171 | kfree(data.pointer); | ||
172 | result = -ENODEV; | ||
173 | goto end; | ||
174 | } | 264 | } |
175 | 265 | ||
176 | end: | 266 | if (!result) { |
177 | kfree(buffer.pointer); | 267 | bif = data->pointer; |
178 | 268 | battery->flags.power_unit = bif->power_unit; | |
179 | if (!result) | 269 | } |
180 | (*bif) = data.pointer; | ||
181 | 270 | ||
182 | return result; | 271 | return result; |
183 | } | 272 | } |
184 | 273 | ||
185 | static int | 274 | static int acpi_battery_get_state(struct acpi_battery *battery) |
186 | acpi_battery_get_state(struct acpi_battery *battery, | ||
187 | struct acpi_battery_state **bst) | ||
188 | { | 275 | { |
189 | int result = 0; | 276 | int result = 0; |
190 | acpi_status status = 0; | 277 | acpi_status status = 0; |
@@ -192,16 +279,17 @@ acpi_battery_get_state(struct acpi_battery *battery, | |||
192 | struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST), | 279 | struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST), |
193 | ACPI_BATTERY_FORMAT_BST | 280 | ACPI_BATTERY_FORMAT_BST |
194 | }; | 281 | }; |
195 | struct acpi_buffer data = { 0, NULL }; | ||
196 | union acpi_object *package = NULL; | 282 | union acpi_object *package = NULL; |
283 | struct acpi_buffer *data = NULL; | ||
197 | 284 | ||
285 | battery->state_update_time = get_seconds(); | ||
198 | 286 | ||
199 | if (!battery || !bst) | 287 | if (!acpi_battery_present(battery)) |
200 | return -EINVAL; | 288 | return 0; |
201 | 289 | ||
202 | /* Evalute _BST */ | 290 | /* Evalute _BST */ |
203 | 291 | ||
204 | status = acpi_evaluate_object(battery->device->handle, "_BST", NULL, &buffer); | 292 | status = acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL, &buffer); |
205 | if (ACPI_FAILURE(status)) { | 293 | if (ACPI_FAILURE(status)) { |
206 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST")); | 294 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST")); |
207 | return -ENODEV; | 295 | return -ENODEV; |
@@ -209,55 +297,46 @@ acpi_battery_get_state(struct acpi_battery *battery, | |||
209 | 297 | ||
210 | package = buffer.pointer; | 298 | package = buffer.pointer; |
211 | 299 | ||
212 | /* Extract Package Data */ | 300 | data = &battery->bst_data; |
213 | 301 | ||
214 | status = acpi_extract_package(package, &format, &data); | 302 | /* Extract Package Data */ |
215 | if (status != AE_BUFFER_OVERFLOW) { | ||
216 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST")); | ||
217 | result = -ENODEV; | ||
218 | goto end; | ||
219 | } | ||
220 | 303 | ||
221 | data.pointer = kzalloc(data.length, GFP_KERNEL); | 304 | result = acpi_battery_extract_package(battery, package, &format, data, "_BST"); |
222 | if (!data.pointer) { | 305 | if (result) |
223 | result = -ENOMEM; | ||
224 | goto end; | 306 | goto end; |
225 | } | ||
226 | 307 | ||
227 | status = acpi_extract_package(package, &format, &data); | 308 | end: |
228 | if (ACPI_FAILURE(status)) { | 309 | if (buffer.pointer) { |
229 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST")); | 310 | kfree(buffer.pointer); |
230 | kfree(data.pointer); | ||
231 | result = -ENODEV; | ||
232 | goto end; | ||
233 | } | 311 | } |
234 | 312 | ||
235 | end: | 313 | return result; |
236 | kfree(buffer.pointer); | 314 | } |
237 | 315 | ||
238 | if (!result) | 316 | static int acpi_battery_get_alarm(struct acpi_battery *battery) |
239 | (*bst) = data.pointer; | 317 | { |
318 | battery->alarm_update_time = get_seconds(); | ||
240 | 319 | ||
241 | return result; | 320 | return 0; |
242 | } | 321 | } |
243 | 322 | ||
244 | static int | 323 | static int acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm) |
245 | acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm) | ||
246 | { | 324 | { |
247 | acpi_status status = 0; | 325 | acpi_status status = 0; |
248 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | 326 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; |
249 | struct acpi_object_list arg_list = { 1, &arg0 }; | 327 | struct acpi_object_list arg_list = { 1, &arg0 }; |
250 | 328 | ||
329 | battery->alarm_update_time = get_seconds(); | ||
251 | 330 | ||
252 | if (!battery) | 331 | if (!acpi_battery_present(battery)) |
253 | return -EINVAL; | 332 | return -ENODEV; |
254 | 333 | ||
255 | if (!battery->flags.alarm) | 334 | if (!acpi_battery_alarm_present(battery)) |
256 | return -ENODEV; | 335 | return -ENODEV; |
257 | 336 | ||
258 | arg0.integer.value = alarm; | 337 | arg0.integer.value = alarm; |
259 | 338 | ||
260 | status = acpi_evaluate_object(battery->device->handle, "_BTP", &arg_list, NULL); | 339 | status = acpi_evaluate_object(acpi_battery_handle(battery), "_BTP", &arg_list, NULL); |
261 | if (ACPI_FAILURE(status)) | 340 | if (ACPI_FAILURE(status)) |
262 | return -ENODEV; | 341 | return -ENODEV; |
263 | 342 | ||
@@ -268,65 +347,110 @@ acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm) | |||
268 | return 0; | 347 | return 0; |
269 | } | 348 | } |
270 | 349 | ||
271 | static int acpi_battery_check(struct acpi_battery *battery) | 350 | static int acpi_battery_init_alarm(struct acpi_battery *battery) |
272 | { | 351 | { |
273 | int result = 0; | 352 | int result = 0; |
274 | acpi_status status = AE_OK; | 353 | acpi_status status = AE_OK; |
275 | acpi_handle handle = NULL; | 354 | acpi_handle handle = NULL; |
276 | struct acpi_device *device = NULL; | 355 | struct acpi_battery_info *bif = battery->bif_data.pointer; |
277 | struct acpi_battery_info *bif = NULL; | 356 | unsigned long alarm = battery->alarm; |
278 | |||
279 | 357 | ||
280 | if (!battery) | 358 | /* See if alarms are supported, and if so, set default */ |
281 | return -EINVAL; | ||
282 | 359 | ||
283 | device = battery->device; | 360 | status = acpi_get_handle(acpi_battery_handle(battery), "_BTP", &handle); |
361 | if (ACPI_SUCCESS(status)) { | ||
362 | acpi_battery_alarm_present(battery) = 1; | ||
363 | if (!alarm && bif) { | ||
364 | alarm = bif->design_capacity_warning; | ||
365 | } | ||
366 | result = acpi_battery_set_alarm(battery, alarm); | ||
367 | if (result) | ||
368 | goto end; | ||
369 | } else { | ||
370 | acpi_battery_alarm_present(battery) = 0; | ||
371 | } | ||
284 | 372 | ||
285 | result = acpi_bus_get_status(device); | 373 | end: |
286 | if (result) | ||
287 | return result; | ||
288 | 374 | ||
289 | /* Insertion? */ | 375 | return result; |
376 | } | ||
290 | 377 | ||
291 | if (!battery->flags.present && device->status.battery_present) { | 378 | static int acpi_battery_init_update(struct acpi_battery *battery) |
379 | { | ||
380 | int result = 0; | ||
292 | 381 | ||
293 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery inserted\n")); | 382 | result = acpi_battery_get_status(battery); |
383 | if (result) | ||
384 | return result; | ||
294 | 385 | ||
295 | /* Evalute _BIF to get certain static information */ | 386 | acpi_battery_present_prev(battery) = acpi_battery_present(battery); |
296 | 387 | ||
297 | result = acpi_battery_get_info(battery, &bif); | 388 | if (acpi_battery_present(battery)) { |
389 | result = acpi_battery_get_info(battery); | ||
390 | if (result) | ||
391 | return result; | ||
392 | result = acpi_battery_get_state(battery); | ||
298 | if (result) | 393 | if (result) |
299 | return result; | 394 | return result; |
300 | 395 | ||
301 | battery->flags.power_unit = bif->power_unit; | 396 | acpi_battery_init_alarm(battery); |
302 | battery->trips.warning = bif->design_capacity_warning; | 397 | } |
303 | battery->trips.low = bif->design_capacity_low; | 398 | |
304 | kfree(bif); | 399 | return result; |
400 | } | ||
401 | |||
402 | static int acpi_battery_update(struct acpi_battery *battery, | ||
403 | int update, int *update_result_ptr) | ||
404 | { | ||
405 | int result = 0; | ||
406 | int update_result = ACPI_BATTERY_NONE_UPDATE; | ||
305 | 407 | ||
306 | /* See if alarms are supported, and if so, set default */ | 408 | if (!acpi_battery_present(battery)) { |
409 | update = 1; | ||
410 | } | ||
307 | 411 | ||
308 | status = acpi_get_handle(battery->device->handle, "_BTP", &handle); | 412 | if (acpi_battery_init_update_flag(battery)) { |
309 | if (ACPI_SUCCESS(status)) { | 413 | result = acpi_battery_init_update(battery); |
310 | battery->flags.alarm = 1; | 414 | if (result) |
311 | acpi_battery_set_alarm(battery, battery->trips.warning); | 415 | goto end;; |
416 | update_result = ACPI_BATTERY_INIT_UPDATE; | ||
417 | } else if (update) { | ||
418 | result = acpi_battery_get_status(battery); | ||
419 | if (result) | ||
420 | goto end;; | ||
421 | if (acpi_battery_inserted(battery) || acpi_battery_removed(battery)) { | ||
422 | result = acpi_battery_init_update(battery); | ||
423 | if (result) | ||
424 | goto end;; | ||
425 | update_result = ACPI_BATTERY_INIT_UPDATE; | ||
426 | } else { | ||
427 | update_result = ACPI_BATTERY_EASY_UPDATE; | ||
312 | } | 428 | } |
313 | } | 429 | } |
314 | 430 | ||
315 | /* Removal? */ | 431 | end: |
316 | 432 | ||
317 | else if (battery->flags.present && !device->status.battery_present) { | 433 | acpi_battery_init_update_flag(battery) = (result != 0); |
318 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery removed\n")); | ||
319 | } | ||
320 | 434 | ||
321 | battery->flags.present = device->status.battery_present; | 435 | *update_result_ptr = update_result; |
322 | 436 | ||
323 | return result; | 437 | return result; |
324 | } | 438 | } |
325 | 439 | ||
326 | static void acpi_battery_check_present(struct acpi_battery *battery) | 440 | static void acpi_battery_notify_update(struct acpi_battery *battery) |
327 | { | 441 | { |
328 | if (!battery->flags.present) { | 442 | acpi_battery_get_status(battery); |
329 | acpi_battery_check(battery); | 443 | |
444 | if (acpi_battery_init_update_flag(battery)) { | ||
445 | return; | ||
446 | } | ||
447 | |||
448 | if (acpi_battery_inserted(battery) || acpi_battery_removed(battery)) { | ||
449 | acpi_battery_init_update_flag(battery) = 1; | ||
450 | } else { | ||
451 | acpi_battery_info_update_flag(battery) = 1; | ||
452 | acpi_battery_state_update_flag(battery) = 1; | ||
453 | acpi_battery_alarm_update_flag(battery) = 1; | ||
330 | } | 454 | } |
331 | } | 455 | } |
332 | 456 | ||
@@ -335,37 +459,33 @@ static void acpi_battery_check_present(struct acpi_battery *battery) | |||
335 | -------------------------------------------------------------------------- */ | 459 | -------------------------------------------------------------------------- */ |
336 | 460 | ||
337 | static struct proc_dir_entry *acpi_battery_dir; | 461 | static struct proc_dir_entry *acpi_battery_dir; |
338 | static int acpi_battery_read_info(struct seq_file *seq, void *offset) | 462 | |
463 | static int acpi_battery_read_info_print(struct seq_file *seq, int result) | ||
339 | { | 464 | { |
340 | int result = 0; | ||
341 | struct acpi_battery *battery = seq->private; | 465 | struct acpi_battery *battery = seq->private; |
342 | struct acpi_battery_info *bif = NULL; | 466 | struct acpi_battery_info *bif = NULL; |
343 | char *units = "?"; | 467 | char *units = "?"; |
344 | 468 | ||
345 | 469 | if (result) | |
346 | if (!battery) | ||
347 | goto end; | 470 | goto end; |
348 | 471 | ||
349 | acpi_battery_check_present(battery); | 472 | if (acpi_battery_present(battery)) |
350 | |||
351 | if (battery->flags.present) | ||
352 | seq_printf(seq, "present: yes\n"); | 473 | seq_printf(seq, "present: yes\n"); |
353 | else { | 474 | else { |
354 | seq_printf(seq, "present: no\n"); | 475 | seq_printf(seq, "present: no\n"); |
355 | goto end; | 476 | goto end; |
356 | } | 477 | } |
357 | 478 | ||
358 | /* Battery Info (_BIF) */ | 479 | bif = battery->bif_data.pointer; |
359 | 480 | if (!bif) { | |
360 | result = acpi_battery_get_info(battery, &bif); | 481 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BIF buffer is NULL")); |
361 | if (result || !bif) { | 482 | result = -ENODEV; |
362 | seq_printf(seq, "ERROR: Unable to read battery information\n"); | ||
363 | goto end; | 483 | goto end; |
364 | } | 484 | } |
365 | 485 | ||
366 | units = | 486 | /* Battery Units */ |
367 | bif-> | 487 | |
368 | power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS; | 488 | units = acpi_battery_power_units(battery); |
369 | 489 | ||
370 | if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) | 490 | if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) |
371 | seq_printf(seq, "design capacity: unknown\n"); | 491 | seq_printf(seq, "design capacity: unknown\n"); |
@@ -396,7 +516,6 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset) | |||
396 | else | 516 | else |
397 | seq_printf(seq, "design voltage: %d mV\n", | 517 | seq_printf(seq, "design voltage: %d mV\n", |
398 | (u32) bif->design_voltage); | 518 | (u32) bif->design_voltage); |
399 | |||
400 | seq_printf(seq, "design capacity warning: %d %sh\n", | 519 | seq_printf(seq, "design capacity warning: %d %sh\n", |
401 | (u32) bif->design_capacity_warning, units); | 520 | (u32) bif->design_capacity_warning, units); |
402 | seq_printf(seq, "design capacity low: %d %sh\n", | 521 | seq_printf(seq, "design capacity low: %d %sh\n", |
@@ -411,9 +530,48 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset) | |||
411 | seq_printf(seq, "OEM info: %s\n", bif->oem_info); | 530 | seq_printf(seq, "OEM info: %s\n", bif->oem_info); |
412 | 531 | ||
413 | end: | 532 | end: |
414 | kfree(bif); | ||
415 | 533 | ||
416 | return 0; | 534 | if (result) |
535 | seq_printf(seq, "ERROR: Unable to read battery info\n"); | ||
536 | |||
537 | return result; | ||
538 | } | ||
539 | |||
540 | static int acpi_battery_read_info(struct seq_file *seq, void *offset) | ||
541 | { | ||
542 | struct acpi_battery *battery = seq->private; | ||
543 | int result = 0; | ||
544 | int update_result = ACPI_BATTERY_NONE_UPDATE; | ||
545 | int update = 0; | ||
546 | |||
547 | acpi_battery_mutex_lock(battery); | ||
548 | |||
549 | update = (get_seconds() - battery->info_update_time >= update_time); | ||
550 | update = (update | acpi_battery_info_update_flag(battery)); | ||
551 | |||
552 | result = acpi_battery_update(battery, update, &update_result); | ||
553 | if (result) | ||
554 | goto end; | ||
555 | |||
556 | /* Battery Info (_BIF) */ | ||
557 | |||
558 | if (update_result == ACPI_BATTERY_EASY_UPDATE) { | ||
559 | result = acpi_battery_get_info(battery); | ||
560 | if (result) | ||
561 | goto end; | ||
562 | } | ||
563 | |||
564 | end: | ||
565 | |||
566 | result = acpi_battery_read_info_print(seq, result); | ||
567 | |||
568 | acpi_battery_check_result(battery, result); | ||
569 | |||
570 | acpi_battery_info_update_flag(battery) = result; | ||
571 | |||
572 | acpi_battery_mutex_unlock(battery); | ||
573 | |||
574 | return result; | ||
417 | } | 575 | } |
418 | 576 | ||
419 | static int acpi_battery_info_open_fs(struct inode *inode, struct file *file) | 577 | static int acpi_battery_info_open_fs(struct inode *inode, struct file *file) |
@@ -421,40 +579,33 @@ static int acpi_battery_info_open_fs(struct inode *inode, struct file *file) | |||
421 | return single_open(file, acpi_battery_read_info, PDE(inode)->data); | 579 | return single_open(file, acpi_battery_read_info, PDE(inode)->data); |
422 | } | 580 | } |
423 | 581 | ||
424 | static int acpi_battery_read_state(struct seq_file *seq, void *offset) | 582 | static int acpi_battery_read_state_print(struct seq_file *seq, int result) |
425 | { | 583 | { |
426 | int result = 0; | ||
427 | struct acpi_battery *battery = seq->private; | 584 | struct acpi_battery *battery = seq->private; |
428 | struct acpi_battery_state *bst = NULL; | 585 | struct acpi_battery_state *bst = NULL; |
429 | char *units = "?"; | 586 | char *units = "?"; |
430 | 587 | ||
431 | 588 | if (result) | |
432 | if (!battery) | ||
433 | goto end; | 589 | goto end; |
434 | 590 | ||
435 | acpi_battery_check_present(battery); | 591 | if (acpi_battery_present(battery)) |
436 | |||
437 | if (battery->flags.present) | ||
438 | seq_printf(seq, "present: yes\n"); | 592 | seq_printf(seq, "present: yes\n"); |
439 | else { | 593 | else { |
440 | seq_printf(seq, "present: no\n"); | 594 | seq_printf(seq, "present: no\n"); |
441 | goto end; | 595 | goto end; |
442 | } | 596 | } |
443 | 597 | ||
444 | /* Battery Units */ | 598 | bst = battery->bst_data.pointer; |
445 | 599 | if (!bst) { | |
446 | units = | 600 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BST buffer is NULL")); |
447 | battery->flags. | 601 | result = -ENODEV; |
448 | power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS; | ||
449 | |||
450 | /* Battery Status (_BST) */ | ||
451 | |||
452 | result = acpi_battery_get_state(battery, &bst); | ||
453 | if (result || !bst) { | ||
454 | seq_printf(seq, "ERROR: Unable to read battery state\n"); | ||
455 | goto end; | 602 | goto end; |
456 | } | 603 | } |
457 | 604 | ||
605 | /* Battery Units */ | ||
606 | |||
607 | units = acpi_battery_power_units(battery); | ||
608 | |||
458 | if (!(bst->state & 0x04)) | 609 | if (!(bst->state & 0x04)) |
459 | seq_printf(seq, "capacity state: ok\n"); | 610 | seq_printf(seq, "capacity state: ok\n"); |
460 | else | 611 | else |
@@ -490,9 +641,49 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset) | |||
490 | (u32) bst->present_voltage); | 641 | (u32) bst->present_voltage); |
491 | 642 | ||
492 | end: | 643 | end: |
493 | kfree(bst); | ||
494 | 644 | ||
495 | return 0; | 645 | if (result) { |
646 | seq_printf(seq, "ERROR: Unable to read battery state\n"); | ||
647 | } | ||
648 | |||
649 | return result; | ||
650 | } | ||
651 | |||
652 | static int acpi_battery_read_state(struct seq_file *seq, void *offset) | ||
653 | { | ||
654 | struct acpi_battery *battery = seq->private; | ||
655 | int result = 0; | ||
656 | int update_result = ACPI_BATTERY_NONE_UPDATE; | ||
657 | int update = 0; | ||
658 | |||
659 | acpi_battery_mutex_lock(battery); | ||
660 | |||
661 | update = (get_seconds() - battery->state_update_time >= update_time); | ||
662 | update = (update | acpi_battery_state_update_flag(battery)); | ||
663 | |||
664 | result = acpi_battery_update(battery, update, &update_result); | ||
665 | if (result) | ||
666 | goto end; | ||
667 | |||
668 | /* Battery State (_BST) */ | ||
669 | |||
670 | if (update_result == ACPI_BATTERY_EASY_UPDATE) { | ||
671 | result = acpi_battery_get_state(battery); | ||
672 | if (result) | ||
673 | goto end; | ||
674 | } | ||
675 | |||
676 | end: | ||
677 | |||
678 | result = acpi_battery_read_state_print(seq, result); | ||
679 | |||
680 | acpi_battery_check_result(battery, result); | ||
681 | |||
682 | acpi_battery_state_update_flag(battery) = result; | ||
683 | |||
684 | acpi_battery_mutex_unlock(battery); | ||
685 | |||
686 | return result; | ||
496 | } | 687 | } |
497 | 688 | ||
498 | static int acpi_battery_state_open_fs(struct inode *inode, struct file *file) | 689 | static int acpi_battery_state_open_fs(struct inode *inode, struct file *file) |
@@ -500,38 +691,72 @@ static int acpi_battery_state_open_fs(struct inode *inode, struct file *file) | |||
500 | return single_open(file, acpi_battery_read_state, PDE(inode)->data); | 691 | return single_open(file, acpi_battery_read_state, PDE(inode)->data); |
501 | } | 692 | } |
502 | 693 | ||
503 | static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) | 694 | static int acpi_battery_read_alarm_print(struct seq_file *seq, int result) |
504 | { | 695 | { |
505 | struct acpi_battery *battery = seq->private; | 696 | struct acpi_battery *battery = seq->private; |
506 | char *units = "?"; | 697 | char *units = "?"; |
507 | 698 | ||
508 | 699 | if (result) | |
509 | if (!battery) | ||
510 | goto end; | 700 | goto end; |
511 | 701 | ||
512 | acpi_battery_check_present(battery); | 702 | if (!acpi_battery_present(battery)) { |
513 | |||
514 | if (!battery->flags.present) { | ||
515 | seq_printf(seq, "present: no\n"); | 703 | seq_printf(seq, "present: no\n"); |
516 | goto end; | 704 | goto end; |
517 | } | 705 | } |
518 | 706 | ||
519 | /* Battery Units */ | 707 | /* Battery Units */ |
520 | 708 | ||
521 | units = | 709 | units = acpi_battery_power_units(battery); |
522 | battery->flags. | ||
523 | power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS; | ||
524 | |||
525 | /* Battery Alarm */ | ||
526 | 710 | ||
527 | seq_printf(seq, "alarm: "); | 711 | seq_printf(seq, "alarm: "); |
528 | if (!battery->alarm) | 712 | if (!battery->alarm) |
529 | seq_printf(seq, "unsupported\n"); | 713 | seq_printf(seq, "unsupported\n"); |
530 | else | 714 | else |
531 | seq_printf(seq, "%d %sh\n", (u32) battery->alarm, units); | 715 | seq_printf(seq, "%lu %sh\n", battery->alarm, units); |
532 | 716 | ||
533 | end: | 717 | end: |
534 | return 0; | 718 | |
719 | if (result) | ||
720 | seq_printf(seq, "ERROR: Unable to read battery alarm\n"); | ||
721 | |||
722 | return result; | ||
723 | } | ||
724 | |||
725 | static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) | ||
726 | { | ||
727 | struct acpi_battery *battery = seq->private; | ||
728 | int result = 0; | ||
729 | int update_result = ACPI_BATTERY_NONE_UPDATE; | ||
730 | int update = 0; | ||
731 | |||
732 | acpi_battery_mutex_lock(battery); | ||
733 | |||
734 | update = (get_seconds() - battery->alarm_update_time >= update_time); | ||
735 | update = (update | acpi_battery_alarm_update_flag(battery)); | ||
736 | |||
737 | result = acpi_battery_update(battery, update, &update_result); | ||
738 | if (result) | ||
739 | goto end; | ||
740 | |||
741 | /* Battery Alarm */ | ||
742 | |||
743 | if (update_result == ACPI_BATTERY_EASY_UPDATE) { | ||
744 | result = acpi_battery_get_alarm(battery); | ||
745 | if (result) | ||
746 | goto end; | ||
747 | } | ||
748 | |||
749 | end: | ||
750 | |||
751 | result = acpi_battery_read_alarm_print(seq, result); | ||
752 | |||
753 | acpi_battery_check_result(battery, result); | ||
754 | |||
755 | acpi_battery_alarm_update_flag(battery) = result; | ||
756 | |||
757 | acpi_battery_mutex_unlock(battery); | ||
758 | |||
759 | return result; | ||
535 | } | 760 | } |
536 | 761 | ||
537 | static ssize_t | 762 | static ssize_t |
@@ -543,27 +768,47 @@ acpi_battery_write_alarm(struct file *file, | |||
543 | char alarm_string[12] = { '\0' }; | 768 | char alarm_string[12] = { '\0' }; |
544 | struct seq_file *m = file->private_data; | 769 | struct seq_file *m = file->private_data; |
545 | struct acpi_battery *battery = m->private; | 770 | struct acpi_battery *battery = m->private; |
771 | int update_result = ACPI_BATTERY_NONE_UPDATE; | ||
546 | 772 | ||
547 | 773 | ||
548 | if (!battery || (count > sizeof(alarm_string) - 1)) | 774 | if (!battery || (count > sizeof(alarm_string) - 1)) |
549 | return -EINVAL; | 775 | return -EINVAL; |
550 | 776 | ||
551 | acpi_battery_check_present(battery); | 777 | acpi_battery_mutex_lock(battery); |
552 | 778 | ||
553 | if (!battery->flags.present) | 779 | result = acpi_battery_update(battery, 1, &update_result); |
554 | return -ENODEV; | 780 | if (result) { |
781 | result = -ENODEV; | ||
782 | goto end; | ||
783 | } | ||
555 | 784 | ||
556 | if (copy_from_user(alarm_string, buffer, count)) | 785 | if (!acpi_battery_present(battery)) { |
557 | return -EFAULT; | 786 | result = -ENODEV; |
787 | goto end; | ||
788 | } | ||
789 | |||
790 | if (copy_from_user(alarm_string, buffer, count)) { | ||
791 | result = -EFAULT; | ||
792 | goto end; | ||
793 | } | ||
558 | 794 | ||
559 | alarm_string[count] = '\0'; | 795 | alarm_string[count] = '\0'; |
560 | 796 | ||
561 | result = acpi_battery_set_alarm(battery, | 797 | result = acpi_battery_set_alarm(battery, |
562 | simple_strtoul(alarm_string, NULL, 0)); | 798 | simple_strtoul(alarm_string, NULL, 0)); |
563 | if (result) | 799 | if (result) |
564 | return result; | 800 | goto end; |
801 | |||
802 | end: | ||
803 | |||
804 | acpi_battery_check_result(battery, result); | ||
565 | 805 | ||
566 | return count; | 806 | if (!result) |
807 | result = count; | ||
808 | |||
809 | acpi_battery_mutex_unlock(battery); | ||
810 | |||
811 | return result; | ||
567 | } | 812 | } |
568 | 813 | ||
569 | static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file) | 814 | static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file) |
@@ -648,7 +893,6 @@ static int acpi_battery_add_fs(struct acpi_device *device) | |||
648 | 893 | ||
649 | static int acpi_battery_remove_fs(struct acpi_device *device) | 894 | static int acpi_battery_remove_fs(struct acpi_device *device) |
650 | { | 895 | { |
651 | |||
652 | if (acpi_device_dir(device)) { | 896 | if (acpi_device_dir(device)) { |
653 | remove_proc_entry(ACPI_BATTERY_FILE_ALARM, | 897 | remove_proc_entry(ACPI_BATTERY_FILE_ALARM, |
654 | acpi_device_dir(device)); | 898 | acpi_device_dir(device)); |
@@ -684,8 +928,11 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) | |||
684 | case ACPI_BATTERY_NOTIFY_INFO: | 928 | case ACPI_BATTERY_NOTIFY_INFO: |
685 | case ACPI_NOTIFY_BUS_CHECK: | 929 | case ACPI_NOTIFY_BUS_CHECK: |
686 | case ACPI_NOTIFY_DEVICE_CHECK: | 930 | case ACPI_NOTIFY_DEVICE_CHECK: |
687 | acpi_battery_check(battery); | 931 | acpi_battery_mutex_lock(battery); |
688 | acpi_bus_generate_event(device, event, battery->flags.present); | 932 | device = battery->device; |
933 | acpi_battery_notify_update(battery); | ||
934 | acpi_battery_mutex_unlock(battery); | ||
935 | acpi_bus_generate_event(device, event, acpi_battery_present(battery)); | ||
689 | break; | 936 | break; |
690 | default: | 937 | default: |
691 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 938 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
@@ -702,7 +949,6 @@ static int acpi_battery_add(struct acpi_device *device) | |||
702 | acpi_status status = 0; | 949 | acpi_status status = 0; |
703 | struct acpi_battery *battery = NULL; | 950 | struct acpi_battery *battery = NULL; |
704 | 951 | ||
705 | |||
706 | if (!device) | 952 | if (!device) |
707 | return -EINVAL; | 953 | return -EINVAL; |
708 | 954 | ||
@@ -710,15 +956,21 @@ static int acpi_battery_add(struct acpi_device *device) | |||
710 | if (!battery) | 956 | if (!battery) |
711 | return -ENOMEM; | 957 | return -ENOMEM; |
712 | 958 | ||
959 | mutex_init(&battery->mutex); | ||
960 | |||
961 | acpi_battery_mutex_lock(battery); | ||
962 | |||
713 | battery->device = device; | 963 | battery->device = device; |
714 | strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); | 964 | strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); |
715 | strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); | 965 | strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); |
716 | acpi_driver_data(device) = battery; | 966 | acpi_driver_data(device) = battery; |
717 | 967 | ||
718 | result = acpi_battery_check(battery); | 968 | result = acpi_battery_get_status(battery); |
719 | if (result) | 969 | if (result) |
720 | goto end; | 970 | goto end; |
721 | 971 | ||
972 | acpi_battery_init_update_flag(battery) = 1; | ||
973 | |||
722 | result = acpi_battery_add_fs(device); | 974 | result = acpi_battery_add_fs(device); |
723 | if (result) | 975 | if (result) |
724 | goto end; | 976 | goto end; |
@@ -727,6 +979,7 @@ static int acpi_battery_add(struct acpi_device *device) | |||
727 | ACPI_ALL_NOTIFY, | 979 | ACPI_ALL_NOTIFY, |
728 | acpi_battery_notify, battery); | 980 | acpi_battery_notify, battery); |
729 | if (ACPI_FAILURE(status)) { | 981 | if (ACPI_FAILURE(status)) { |
982 | ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler")); | ||
730 | result = -ENODEV; | 983 | result = -ENODEV; |
731 | goto end; | 984 | goto end; |
732 | } | 985 | } |
@@ -736,11 +989,14 @@ static int acpi_battery_add(struct acpi_device *device) | |||
736 | device->status.battery_present ? "present" : "absent"); | 989 | device->status.battery_present ? "present" : "absent"); |
737 | 990 | ||
738 | end: | 991 | end: |
992 | |||
739 | if (result) { | 993 | if (result) { |
740 | acpi_battery_remove_fs(device); | 994 | acpi_battery_remove_fs(device); |
741 | kfree(battery); | 995 | kfree(battery); |
742 | } | 996 | } |
743 | 997 | ||
998 | acpi_battery_mutex_unlock(battery); | ||
999 | |||
744 | return result; | 1000 | return result; |
745 | } | 1001 | } |
746 | 1002 | ||
@@ -749,18 +1005,29 @@ static int acpi_battery_remove(struct acpi_device *device, int type) | |||
749 | acpi_status status = 0; | 1005 | acpi_status status = 0; |
750 | struct acpi_battery *battery = NULL; | 1006 | struct acpi_battery *battery = NULL; |
751 | 1007 | ||
752 | |||
753 | if (!device || !acpi_driver_data(device)) | 1008 | if (!device || !acpi_driver_data(device)) |
754 | return -EINVAL; | 1009 | return -EINVAL; |
755 | 1010 | ||
756 | battery = acpi_driver_data(device); | 1011 | battery = acpi_driver_data(device); |
757 | 1012 | ||
1013 | acpi_battery_mutex_lock(battery); | ||
1014 | |||
758 | status = acpi_remove_notify_handler(device->handle, | 1015 | status = acpi_remove_notify_handler(device->handle, |
759 | ACPI_ALL_NOTIFY, | 1016 | ACPI_ALL_NOTIFY, |
760 | acpi_battery_notify); | 1017 | acpi_battery_notify); |
761 | 1018 | ||
762 | acpi_battery_remove_fs(device); | 1019 | acpi_battery_remove_fs(device); |
763 | 1020 | ||
1021 | if (battery->bif_data.pointer) | ||
1022 | kfree(battery->bif_data.pointer); | ||
1023 | |||
1024 | if (battery->bst_data.pointer) | ||
1025 | kfree(battery->bst_data.pointer); | ||
1026 | |||
1027 | acpi_battery_mutex_unlock(battery); | ||
1028 | |||
1029 | mutex_destroy(&battery->mutex); | ||
1030 | |||
764 | kfree(battery); | 1031 | kfree(battery); |
765 | 1032 | ||
766 | return 0; | 1033 | return 0; |
@@ -775,7 +1042,10 @@ static int acpi_battery_resume(struct acpi_device *device) | |||
775 | return -EINVAL; | 1042 | return -EINVAL; |
776 | 1043 | ||
777 | battery = device->driver_data; | 1044 | battery = device->driver_data; |
778 | return acpi_battery_check(battery); | 1045 | |
1046 | acpi_battery_init_update_flag(battery) = 1; | ||
1047 | |||
1048 | return 0; | ||
779 | } | 1049 | } |
780 | 1050 | ||
781 | static int __init acpi_battery_init(void) | 1051 | static int __init acpi_battery_init(void) |
@@ -800,7 +1070,6 @@ static int __init acpi_battery_init(void) | |||
800 | 1070 | ||
801 | static void __exit acpi_battery_exit(void) | 1071 | static void __exit acpi_battery_exit(void) |
802 | { | 1072 | { |
803 | |||
804 | acpi_bus_unregister_driver(&acpi_battery_driver); | 1073 | acpi_bus_unregister_driver(&acpi_battery_driver); |
805 | 1074 | ||
806 | acpi_unlock_battery_dir(acpi_battery_dir); | 1075 | acpi_unlock_battery_dir(acpi_battery_dir); |