aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/battery.c
diff options
context:
space:
mode:
authorAlexey Starikovskiy <astarikovskiy@suse.de>2007-09-26 11:42:52 -0400
committerLen Brown <len.brown@intel.com>2007-09-27 15:50:21 -0400
commitf1d4661abe05d0a2c014166042d15ed8b69ae8f2 (patch)
tree88d0e0ae5bde3afc5cb1baa2b10ea79e2958db81 /drivers/acpi/battery.c
parent038fdea2960be53f82353fd409526fb77a558c52 (diff)
ACPI: Battery: simplify update scheme
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/battery.c')
-rw-r--r--drivers/acpi/battery.c280
1 files changed, 57 insertions, 223 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index de506f39d3bd..faa70a50b807 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -27,6 +27,7 @@
27#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/init.h> 28#include <linux/init.h>
29#include <linux/types.h> 29#include <linux/types.h>
30#include <linux/jiffies.h>
30#include <linux/proc_fs.h> 31#include <linux/proc_fs.h>
31#include <linux/seq_file.h> 32#include <linux/seq_file.h>
32#include <asm/uaccess.h> 33#include <asm/uaccess.h>
@@ -41,27 +42,18 @@
41#define ACPI_BATTERY_DEVICE_NAME "Battery" 42#define ACPI_BATTERY_DEVICE_NAME "Battery"
42#define ACPI_BATTERY_NOTIFY_STATUS 0x80 43#define ACPI_BATTERY_NOTIFY_STATUS 0x80
43#define ACPI_BATTERY_NOTIFY_INFO 0x81 44#define ACPI_BATTERY_NOTIFY_INFO 0x81
44#define ACPI_BATTERY_UNITS_WATTS "mW"
45#define ACPI_BATTERY_UNITS_AMPS "mA"
46 45
47#define _COMPONENT ACPI_BATTERY_COMPONENT 46#define _COMPONENT ACPI_BATTERY_COMPONENT
48 47
49#define ACPI_BATTERY_UPDATE_TIME 0
50
51#define ACPI_BATTERY_NONE_UPDATE 0
52#define ACPI_BATTERY_EASY_UPDATE 1
53#define ACPI_BATTERY_INIT_UPDATE 2
54
55ACPI_MODULE_NAME("battery"); 48ACPI_MODULE_NAME("battery");
56 49
57MODULE_AUTHOR("Paul Diefenbaugh"); 50MODULE_AUTHOR("Paul Diefenbaugh");
58MODULE_DESCRIPTION("ACPI Battery Driver"); 51MODULE_DESCRIPTION("ACPI Battery Driver");
59MODULE_LICENSE("GPL"); 52MODULE_LICENSE("GPL");
60 53
61static unsigned int update_time = ACPI_BATTERY_UPDATE_TIME; 54static unsigned int cache_time = 1000;
62 55module_param(cache_time, uint, 0644);
63/* 0 - every time, > 0 - by update_time */ 56MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
64module_param(update_time, uint, 0644);
65 57
66extern struct proc_dir_entry *acpi_lock_battery_dir(void); 58extern struct proc_dir_entry *acpi_lock_battery_dir(void);
67extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); 59extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
@@ -95,15 +87,12 @@ enum acpi_battery_files {
95}; 87};
96 88
97struct acpi_battery { 89struct acpi_battery {
98 struct acpi_device *device;
99 struct mutex lock; 90 struct mutex lock;
100 unsigned long alarm; 91 struct acpi_device *device;
101 unsigned long update_time[ACPI_BATTERY_NUMFILES]; 92 unsigned long update_time;
102 int state;
103 int present_rate; 93 int present_rate;
104 int remaining_capacity; 94 int remaining_capacity;
105 int present_voltage; 95 int present_voltage;
106 int power_unit;
107 int design_capacity; 96 int design_capacity;
108 int last_full_capacity; 97 int last_full_capacity;
109 int technology; 98 int technology;
@@ -112,14 +101,14 @@ struct acpi_battery {
112 int design_capacity_low; 101 int design_capacity_low;
113 int capacity_granularity_1; 102 int capacity_granularity_1;
114 int capacity_granularity_2; 103 int capacity_granularity_2;
104 int alarm;
115 char model_number[32]; 105 char model_number[32];
116 char serial_number[32]; 106 char serial_number[32];
117 char type[32]; 107 char type[32];
118 char oem_info[32]; 108 char oem_info[32];
119 u8 present_prev; 109 int state;
110 int power_unit;
120 u8 alarm_present; 111 u8 alarm_present;
121 u8 init_update;
122 u8 update[ACPI_BATTERY_NUMFILES];
123}; 112};
124 113
125inline int acpi_battery_present(struct acpi_battery *battery) 114inline int acpi_battery_present(struct acpi_battery *battery)
@@ -127,33 +116,15 @@ inline int acpi_battery_present(struct acpi_battery *battery)
127 return battery->device->status.battery_present; 116 return battery->device->status.battery_present;
128} 117}
129 118
130inline char *acpi_battery_power_units(struct acpi_battery *battery) 119inline char *acpi_battery_units(struct acpi_battery *battery)
131{ 120{
132 if (battery->power_unit) 121 return (battery->power_unit)?"mA":"mW";
133 return ACPI_BATTERY_UNITS_AMPS;
134 else
135 return ACPI_BATTERY_UNITS_WATTS;
136}
137
138inline acpi_handle acpi_battery_handle(struct acpi_battery *battery)
139{
140 return battery->device->handle;
141} 122}
142 123
143/* -------------------------------------------------------------------------- 124/* --------------------------------------------------------------------------
144 Battery Management 125 Battery Management
145 -------------------------------------------------------------------------- */ 126 -------------------------------------------------------------------------- */
146 127
147static void acpi_battery_check_result(struct acpi_battery *battery, int result)
148{
149 if (!battery)
150 return;
151
152 if (result) {
153 battery->init_update = 1;
154 }
155}
156
157struct acpi_offsets { 128struct acpi_offsets {
158 size_t offset; /* offset inside struct acpi_sbs_battery */ 129 size_t offset; /* offset inside struct acpi_sbs_battery */
159 u8 mode; /* int or string? */ 130 u8 mode; /* int or string? */
@@ -228,11 +199,10 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
228 acpi_status status = 0; 199 acpi_status status = 0;
229 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 200 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
230 201
231 battery->update_time[ACPI_BATTERY_INFO] = get_seconds();
232 if (!acpi_battery_present(battery)) 202 if (!acpi_battery_present(battery))
233 return 0; 203 return 0;
234 mutex_lock(&battery->lock); 204 mutex_lock(&battery->lock);
235 status = acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", 205 status = acpi_evaluate_object(battery->device->handle, "_BIF",
236 NULL, &buffer); 206 NULL, &buffer);
237 mutex_unlock(&battery->lock); 207 mutex_unlock(&battery->lock);
238 if (ACPI_FAILURE(status)) { 208 if (ACPI_FAILURE(status)) {
@@ -251,13 +221,16 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
251 acpi_status status = 0; 221 acpi_status status = 0;
252 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 222 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
253 223
254 battery->update_time[ACPI_BATTERY_STATE] = get_seconds();
255
256 if (!acpi_battery_present(battery)) 224 if (!acpi_battery_present(battery))
257 return 0; 225 return 0;
258 226
227 if (battery->update_time &&
228 time_before(jiffies, battery->update_time +
229 msecs_to_jiffies(cache_time)))
230 return 0;
231
259 mutex_lock(&battery->lock); 232 mutex_lock(&battery->lock);
260 status = acpi_evaluate_object(acpi_battery_handle(battery), "_BST", 233 status = acpi_evaluate_object(battery->device->handle, "_BST",
261 NULL, &buffer); 234 NULL, &buffer);
262 mutex_unlock(&battery->lock); 235 mutex_unlock(&battery->lock);
263 236
@@ -267,14 +240,13 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
267 } 240 }
268 result = extract_package(battery, buffer.pointer, 241 result = extract_package(battery, buffer.pointer,
269 state_offsets, ARRAY_SIZE(state_offsets)); 242 state_offsets, ARRAY_SIZE(state_offsets));
243 battery->update_time = jiffies;
270 kfree(buffer.pointer); 244 kfree(buffer.pointer);
271 return result; 245 return result;
272} 246}
273 247
274static int acpi_battery_get_alarm(struct acpi_battery *battery) 248static int acpi_battery_get_alarm(struct acpi_battery *battery)
275{ 249{
276 battery->update_time[ACPI_BATTERY_ALARM] = get_seconds();
277
278 return 0; 250 return 0;
279} 251}
280 252
@@ -285,8 +257,6 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery,
285 union acpi_object arg0 = { ACPI_TYPE_INTEGER }; 257 union acpi_object arg0 = { ACPI_TYPE_INTEGER };
286 struct acpi_object_list arg_list = { 1, &arg0 }; 258 struct acpi_object_list arg_list = { 1, &arg0 };
287 259
288 battery->update_time[ACPI_BATTERY_ALARM] = get_seconds();
289
290 if (!acpi_battery_present(battery)) 260 if (!acpi_battery_present(battery))
291 return -ENODEV; 261 return -ENODEV;
292 262
@@ -296,8 +266,8 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery,
296 arg0.integer.value = alarm; 266 arg0.integer.value = alarm;
297 267
298 mutex_lock(&battery->lock); 268 mutex_lock(&battery->lock);
299 status = acpi_evaluate_object(acpi_battery_handle(battery), "_BTP", 269 status = acpi_evaluate_object(battery->device->handle, "_BTP",
300 &arg_list, NULL); 270 &arg_list, NULL);
301 mutex_unlock(&battery->lock); 271 mutex_unlock(&battery->lock);
302 if (ACPI_FAILURE(status)) 272 if (ACPI_FAILURE(status))
303 return -ENODEV; 273 return -ENODEV;
@@ -311,112 +281,36 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery,
311 281
312static int acpi_battery_init_alarm(struct acpi_battery *battery) 282static int acpi_battery_init_alarm(struct acpi_battery *battery)
313{ 283{
314 int result = 0;
315 acpi_status status = AE_OK; 284 acpi_status status = AE_OK;
316 acpi_handle handle = NULL; 285 acpi_handle handle = NULL;
317 unsigned long alarm = battery->alarm;
318 286
319 /* See if alarms are supported, and if so, set default */ 287 /* See if alarms are supported, and if so, set default */
320 288 status = acpi_get_handle(battery->device->handle, "_BTP", &handle);
321 status = acpi_get_handle(acpi_battery_handle(battery), "_BTP", &handle); 289 if (ACPI_FAILURE(status)) {
322 if (ACPI_SUCCESS(status)) {
323 battery->alarm_present = 1;
324 if (!alarm) {
325 alarm = battery->design_capacity_warning;
326 }
327 result = acpi_battery_set_alarm(battery, alarm);
328 if (result)
329 goto end;
330 } else {
331 battery->alarm_present = 0; 290 battery->alarm_present = 0;
291 return 0;
332 } 292 }
333 293 battery->alarm_present = 1;
334 end: 294 if (!battery->alarm)
335 295 battery->alarm = battery->design_capacity_warning;
336 return result; 296 return acpi_battery_set_alarm(battery, battery->alarm);
337} 297}
338 298
339static int acpi_battery_init_update(struct acpi_battery *battery) 299static int acpi_battery_update(struct acpi_battery *battery)
340{ 300{
341 int result = 0; 301 int saved_present = acpi_battery_present(battery);
342 302 int result = acpi_battery_get_status(battery);
343 result = acpi_battery_get_status(battery); 303 if (result || !acpi_battery_present(battery))
344 if (result)
345 return result; 304 return result;
346 305 if (saved_present != acpi_battery_present(battery) ||
347 battery->present_prev = acpi_battery_present(battery); 306 !battery->update_time) {
348 307 battery->update_time = 0;
349 if (acpi_battery_present(battery)) {
350 result = acpi_battery_get_info(battery); 308 result = acpi_battery_get_info(battery);
351 if (result) 309 if (result)
352 return result; 310 return result;
353 result = acpi_battery_get_state(battery);
354 if (result)
355 return result;
356
357 acpi_battery_init_alarm(battery); 311 acpi_battery_init_alarm(battery);
358 } 312 }
359 313 return acpi_battery_get_state(battery);
360 return result;
361}
362
363static int acpi_battery_update(struct acpi_battery *battery,
364 int update, int *update_result_ptr)
365{
366 int result = 0;
367 int update_result = ACPI_BATTERY_NONE_UPDATE;
368
369 if (!acpi_battery_present(battery)) {
370 update = 1;
371 }
372
373 if (battery->init_update) {
374 result = acpi_battery_init_update(battery);
375 if (result)
376 goto end;
377 update_result = ACPI_BATTERY_INIT_UPDATE;
378 } else if (update) {
379 result = acpi_battery_get_status(battery);
380 if (result)
381 goto end;
382 if ((!battery->present_prev & acpi_battery_present(battery))
383 || (battery->present_prev & !acpi_battery_present(battery))) {
384 result = acpi_battery_init_update(battery);
385 if (result)
386 goto end;
387 update_result = ACPI_BATTERY_INIT_UPDATE;
388 } else {
389 update_result = ACPI_BATTERY_EASY_UPDATE;
390 }
391 }
392
393 end:
394
395 battery->init_update = (result != 0);
396
397 *update_result_ptr = update_result;
398
399 return result;
400}
401
402static void acpi_battery_notify_update(struct acpi_battery *battery)
403{
404 acpi_battery_get_status(battery);
405
406 if (battery->init_update) {
407 return;
408 }
409
410 if ((!battery->present_prev &
411 acpi_battery_present(battery)) ||
412 (battery->present_prev &
413 !acpi_battery_present(battery))) {
414 battery->init_update = 1;
415 } else {
416 battery->update[ACPI_BATTERY_INFO] = 1;
417 battery->update[ACPI_BATTERY_STATE] = 1;
418 battery->update[ACPI_BATTERY_ALARM] = 1;
419 }
420} 314}
421 315
422/* -------------------------------------------------------------------------- 316/* --------------------------------------------------------------------------
@@ -442,7 +336,7 @@ static int acpi_battery_print_info(struct seq_file *seq, int result)
442 336
443 /* Battery Units */ 337 /* Battery Units */
444 338
445 units = acpi_battery_power_units(battery); 339 units = acpi_battery_units(battery);
446 340
447 if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) 341 if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
448 seq_printf(seq, "design capacity: unknown\n"); 342 seq_printf(seq, "design capacity: unknown\n");
@@ -511,7 +405,7 @@ static int acpi_battery_print_state(struct seq_file *seq, int result)
511 405
512 /* Battery Units */ 406 /* Battery Units */
513 407
514 units = acpi_battery_power_units(battery); 408 units = acpi_battery_units(battery);
515 409
516 if (!(battery->state & 0x04)) 410 if (!(battery->state & 0x04))
517 seq_printf(seq, "capacity state: ok\n"); 411 seq_printf(seq, "capacity state: ok\n");
@@ -571,13 +465,13 @@ static int acpi_battery_print_alarm(struct seq_file *seq, int result)
571 465
572 /* Battery Units */ 466 /* Battery Units */
573 467
574 units = acpi_battery_power_units(battery); 468 units = acpi_battery_units(battery);
575 469
576 seq_printf(seq, "alarm: "); 470 seq_printf(seq, "alarm: ");
577 if (!battery->alarm) 471 if (!battery->alarm)
578 seq_printf(seq, "unsupported\n"); 472 seq_printf(seq, "unsupported\n");
579 else 473 else
580 seq_printf(seq, "%lu %sh\n", battery->alarm, units); 474 seq_printf(seq, "%u %sh\n", battery->alarm, units);
581 475
582 end: 476 end:
583 477
@@ -587,49 +481,35 @@ static int acpi_battery_print_alarm(struct seq_file *seq, int result)
587 return result; 481 return result;
588} 482}
589 483
590static ssize_t 484static ssize_t acpi_battery_write_alarm(struct file *file,
591acpi_battery_write_alarm(struct file *file, 485 const char __user * buffer,
592 const char __user * buffer, 486 size_t count, loff_t * ppos)
593 size_t count, loff_t * ppos)
594{ 487{
595 int result = 0; 488 int result = 0;
596 char alarm_string[12] = { '\0' }; 489 char alarm_string[12] = { '\0' };
597 struct seq_file *m = file->private_data; 490 struct seq_file *m = file->private_data;
598 struct acpi_battery *battery = m->private; 491 struct acpi_battery *battery = m->private;
599 int update_result = ACPI_BATTERY_NONE_UPDATE;
600 492
601 if (!battery || (count > sizeof(alarm_string) - 1)) 493 if (!battery || (count > sizeof(alarm_string) - 1))
602 return -EINVAL; 494 return -EINVAL;
603
604 result = acpi_battery_update(battery, 1, &update_result);
605 if (result) { 495 if (result) {
606 result = -ENODEV; 496 result = -ENODEV;
607 goto end; 497 goto end;
608 } 498 }
609
610 if (!acpi_battery_present(battery)) { 499 if (!acpi_battery_present(battery)) {
611 result = -ENODEV; 500 result = -ENODEV;
612 goto end; 501 goto end;
613 } 502 }
614
615 if (copy_from_user(alarm_string, buffer, count)) { 503 if (copy_from_user(alarm_string, buffer, count)) {
616 result = -EFAULT; 504 result = -EFAULT;
617 goto end; 505 goto end;
618 } 506 }
619
620 alarm_string[count] = '\0'; 507 alarm_string[count] = '\0';
621 508 battery->alarm = simple_strtol(alarm_string, NULL, 0);
622 result = acpi_battery_set_alarm(battery, 509 result = acpi_battery_set_alarm(battery, battery->alarm);
623 simple_strtoul(alarm_string, NULL, 0));
624 if (result)
625 goto end;
626
627 end: 510 end:
628
629 acpi_battery_check_result(battery, result);
630
631 if (!result) 511 if (!result)
632 result = count; 512 return count;
633 return result; 513 return result;
634} 514}
635 515
@@ -648,28 +528,8 @@ static struct acpi_read_mux {
648static int acpi_battery_read(int fid, struct seq_file *seq) 528static int acpi_battery_read(int fid, struct seq_file *seq)
649{ 529{
650 struct acpi_battery *battery = seq->private; 530 struct acpi_battery *battery = seq->private;
651 int result = 0; 531 int result = acpi_battery_update(battery);
652 int update_result = ACPI_BATTERY_NONE_UPDATE; 532 return acpi_read_funcs[fid].print(seq, result);
653 int update = 0;
654
655 update = (get_seconds() - battery->update_time[fid] >= update_time);
656 update = (update | battery->update[fid]);
657
658 result = acpi_battery_update(battery, update, &update_result);
659 if (result)
660 goto end;
661
662 if (update_result == ACPI_BATTERY_EASY_UPDATE) {
663 result = acpi_read_funcs[fid].get(battery);
664 if (result)
665 goto end;
666 }
667
668 end:
669 result = acpi_read_funcs[fid].print(seq, result);
670 acpi_battery_check_result(battery, result);
671 battery->update[fid] = result;
672 return result;
673} 533}
674 534
675static int acpi_battery_read_info(struct seq_file *seq, void *offset) 535static int acpi_battery_read_info(struct seq_file *seq, void *offset)
@@ -793,33 +653,16 @@ static int acpi_battery_remove_fs(struct acpi_device *device)
793static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) 653static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
794{ 654{
795 struct acpi_battery *battery = data; 655 struct acpi_battery *battery = data;
796 struct acpi_device *device = NULL; 656 struct acpi_device *device;
797
798 if (!battery) 657 if (!battery)
799 return; 658 return;
800
801 device = battery->device; 659 device = battery->device;
802 660 acpi_battery_update(battery);
803 switch (event) { 661 acpi_bus_generate_proc_event(device, event,
804 case ACPI_BATTERY_NOTIFY_STATUS: 662 acpi_battery_present(battery));
805 case ACPI_BATTERY_NOTIFY_INFO: 663 acpi_bus_generate_netlink_event(device->pnp.device_class,
806 case ACPI_NOTIFY_BUS_CHECK: 664 device->dev.bus_id, event,
807 case ACPI_NOTIFY_DEVICE_CHECK:
808 device = battery->device;
809 acpi_battery_notify_update(battery);
810 acpi_bus_generate_proc_event(device, event,
811 acpi_battery_present(battery)); 665 acpi_battery_present(battery));
812 acpi_bus_generate_netlink_event(device->pnp.device_class,
813 device->dev.bus_id, event,
814 acpi_battery_present(battery));
815 break;
816 default:
817 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
818 "Unsupported event [0x%x]\n", event));
819 break;
820 }
821
822 return;
823} 666}
824 667
825static int acpi_battery_add(struct acpi_device *device) 668static int acpi_battery_add(struct acpi_device *device)
@@ -840,12 +683,7 @@ static int acpi_battery_add(struct acpi_device *device)
840 strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); 683 strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
841 acpi_driver_data(device) = battery; 684 acpi_driver_data(device) = battery;
842 mutex_init(&battery->lock); 685 mutex_init(&battery->lock);
843 result = acpi_battery_get_status(battery); 686 acpi_battery_update(battery);
844 if (result)
845 goto end;
846
847 battery->init_update = 1;
848
849 result = acpi_battery_add_fs(device); 687 result = acpi_battery_add_fs(device);
850 if (result) 688 if (result)
851 goto end; 689 goto end;
@@ -898,14 +736,10 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
898static int acpi_battery_resume(struct acpi_device *device) 736static int acpi_battery_resume(struct acpi_device *device)
899{ 737{
900 struct acpi_battery *battery; 738 struct acpi_battery *battery;
901
902 if (!device) 739 if (!device)
903 return -EINVAL; 740 return -EINVAL;
904 741 battery = acpi_driver_data(device);
905 battery = device->driver_data; 742 battery->update_time = 0;
906
907 battery->init_update = 1;
908
909 return 0; 743 return 0;
910} 744}
911 745