aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/battery.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/battery.c')
-rw-r--r--drivers/acpi/battery.c192
1 files changed, 111 insertions, 81 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 681e26b56b11..7d6be23eff89 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -31,7 +31,7 @@
31#include <linux/types.h> 31#include <linux/types.h>
32#include <linux/jiffies.h> 32#include <linux/jiffies.h>
33 33
34#ifdef CONFIG_ACPI_PROCFS 34#ifdef CONFIG_ACPI_PROCFS_POWER
35#include <linux/proc_fs.h> 35#include <linux/proc_fs.h>
36#include <linux/seq_file.h> 36#include <linux/seq_file.h>
37#include <asm/uaccess.h> 37#include <asm/uaccess.h>
@@ -63,7 +63,7 @@ static unsigned int cache_time = 1000;
63module_param(cache_time, uint, 0644); 63module_param(cache_time, uint, 0644);
64MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); 64MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
65 65
66#ifdef CONFIG_ACPI_PROCFS 66#ifdef CONFIG_ACPI_PROCFS_POWER
67extern struct proc_dir_entry *acpi_lock_battery_dir(void); 67extern struct proc_dir_entry *acpi_lock_battery_dir(void);
68extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); 68extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
69 69
@@ -125,19 +125,25 @@ static int acpi_battery_technology(struct acpi_battery *battery)
125 return POWER_SUPPLY_TECHNOLOGY_NiMH; 125 return POWER_SUPPLY_TECHNOLOGY_NiMH;
126 if (!strcasecmp("LION", battery->type)) 126 if (!strcasecmp("LION", battery->type))
127 return POWER_SUPPLY_TECHNOLOGY_LION; 127 return POWER_SUPPLY_TECHNOLOGY_LION;
128 if (!strcasecmp("LI-ION", battery->type))
129 return POWER_SUPPLY_TECHNOLOGY_LION;
128 if (!strcasecmp("LiP", battery->type)) 130 if (!strcasecmp("LiP", battery->type))
129 return POWER_SUPPLY_TECHNOLOGY_LIPO; 131 return POWER_SUPPLY_TECHNOLOGY_LIPO;
130 return POWER_SUPPLY_TECHNOLOGY_UNKNOWN; 132 return POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
131} 133}
132 134
135static int acpi_battery_get_state(struct acpi_battery *battery);
136
133static int acpi_battery_get_property(struct power_supply *psy, 137static int acpi_battery_get_property(struct power_supply *psy,
134 enum power_supply_property psp, 138 enum power_supply_property psp,
135 union power_supply_propval *val) 139 union power_supply_propval *val)
136{ 140{
137 struct acpi_battery *battery = to_acpi_battery(psy); 141 struct acpi_battery *battery = to_acpi_battery(psy);
138 142
139 if ((!acpi_battery_present(battery)) && 143 if (acpi_battery_present(battery)) {
140 psp != POWER_SUPPLY_PROP_PRESENT) 144 /* run battery update only if it is present */
145 acpi_battery_get_state(battery);
146 } else if (psp != POWER_SUPPLY_PROP_PRESENT)
141 return -ENODEV; 147 return -ENODEV;
142 switch (psp) { 148 switch (psp) {
143 case POWER_SUPPLY_PROP_STATUS: 149 case POWER_SUPPLY_PROP_STATUS:
@@ -147,6 +153,8 @@ static int acpi_battery_get_property(struct power_supply *psy,
147 val->intval = POWER_SUPPLY_STATUS_CHARGING; 153 val->intval = POWER_SUPPLY_STATUS_CHARGING;
148 else if (battery->state == 0) 154 else if (battery->state == 0)
149 val->intval = POWER_SUPPLY_STATUS_FULL; 155 val->intval = POWER_SUPPLY_STATUS_FULL;
156 else
157 val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
150 break; 158 break;
151 case POWER_SUPPLY_PROP_PRESENT: 159 case POWER_SUPPLY_PROP_PRESENT:
152 val->intval = acpi_battery_present(battery); 160 val->intval = acpi_battery_present(battery);
@@ -215,7 +223,7 @@ static enum power_supply_property energy_battery_props[] = {
215 POWER_SUPPLY_PROP_MANUFACTURER, 223 POWER_SUPPLY_PROP_MANUFACTURER,
216}; 224};
217 225
218#ifdef CONFIG_ACPI_PROCFS 226#ifdef CONFIG_ACPI_PROCFS_POWER
219inline char *acpi_battery_units(struct acpi_battery *battery) 227inline char *acpi_battery_units(struct acpi_battery *battery)
220{ 228{
221 return (battery->power_unit)?"mA":"mW"; 229 return (battery->power_unit)?"mA":"mW";
@@ -257,7 +265,7 @@ static int extract_package(struct acpi_battery *battery,
257 union acpi_object *package, 265 union acpi_object *package,
258 struct acpi_offsets *offsets, int num) 266 struct acpi_offsets *offsets, int num)
259{ 267{
260 int i, *x; 268 int i;
261 union acpi_object *element; 269 union acpi_object *element;
262 if (package->type != ACPI_TYPE_PACKAGE) 270 if (package->type != ACPI_TYPE_PACKAGE)
263 return -EFAULT; 271 return -EFAULT;
@@ -266,16 +274,21 @@ static int extract_package(struct acpi_battery *battery,
266 return -EFAULT; 274 return -EFAULT;
267 element = &package->package.elements[i]; 275 element = &package->package.elements[i];
268 if (offsets[i].mode) { 276 if (offsets[i].mode) {
269 if (element->type != ACPI_TYPE_STRING && 277 u8 *ptr = (u8 *)battery + offsets[i].offset;
270 element->type != ACPI_TYPE_BUFFER) 278 if (element->type == ACPI_TYPE_STRING ||
271 return -EFAULT; 279 element->type == ACPI_TYPE_BUFFER)
272 strncpy((u8 *)battery + offsets[i].offset, 280 strncpy(ptr, element->string.pointer, 32);
273 element->string.pointer, 32); 281 else if (element->type == ACPI_TYPE_INTEGER) {
282 strncpy(ptr, (u8 *)&element->integer.value,
283 sizeof(acpi_integer));
284 ptr[sizeof(acpi_integer)] = 0;
285 } else return -EFAULT;
274 } else { 286 } else {
275 if (element->type != ACPI_TYPE_INTEGER) 287 if (element->type == ACPI_TYPE_INTEGER) {
276 return -EFAULT; 288 int *x = (int *)((u8 *)battery +
277 x = (int *)((u8 *)battery + offsets[i].offset); 289 offsets[i].offset);
278 *x = element->integer.value; 290 *x = element->integer.value;
291 } else return -EFAULT;
279 } 292 }
280 } 293 }
281 return 0; 294 return 0;
@@ -385,29 +398,82 @@ static int acpi_battery_init_alarm(struct acpi_battery *battery)
385 return acpi_battery_set_alarm(battery); 398 return acpi_battery_set_alarm(battery);
386} 399}
387 400
401static ssize_t acpi_battery_alarm_show(struct device *dev,
402 struct device_attribute *attr,
403 char *buf)
404{
405 struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
406 return sprintf(buf, "%d\n", battery->alarm * 1000);
407}
408
409static ssize_t acpi_battery_alarm_store(struct device *dev,
410 struct device_attribute *attr,
411 const char *buf, size_t count)
412{
413 unsigned long x;
414 struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
415 if (sscanf(buf, "%ld\n", &x) == 1)
416 battery->alarm = x/1000;
417 if (acpi_battery_present(battery))
418 acpi_battery_set_alarm(battery);
419 return count;
420}
421
422static struct device_attribute alarm_attr = {
423 .attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE},
424 .show = acpi_battery_alarm_show,
425 .store = acpi_battery_alarm_store,
426};
427
428static int sysfs_add_battery(struct acpi_battery *battery)
429{
430 int result;
431
432 battery->update_time = 0;
433 result = acpi_battery_get_info(battery);
434 acpi_battery_init_alarm(battery);
435 if (result)
436 return result;
437 if (battery->power_unit) {
438 battery->bat.properties = charge_battery_props;
439 battery->bat.num_properties =
440 ARRAY_SIZE(charge_battery_props);
441 } else {
442 battery->bat.properties = energy_battery_props;
443 battery->bat.num_properties =
444 ARRAY_SIZE(energy_battery_props);
445 }
446
447 battery->bat.name = acpi_device_bid(battery->device);
448 battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;
449 battery->bat.get_property = acpi_battery_get_property;
450
451 result = power_supply_register(&battery->device->dev, &battery->bat);
452 if (result)
453 return result;
454 return device_create_file(battery->bat.dev, &alarm_attr);
455}
456
457static void sysfs_remove_battery(struct acpi_battery *battery)
458{
459 if (!battery->bat.dev)
460 return;
461 device_remove_file(battery->bat.dev, &alarm_attr);
462 power_supply_unregister(&battery->bat);
463 battery->bat.dev = NULL;
464}
465
388static int acpi_battery_update(struct acpi_battery *battery) 466static int acpi_battery_update(struct acpi_battery *battery)
389{ 467{
390 int saved_present = acpi_battery_present(battery);
391 int result = acpi_battery_get_status(battery); 468 int result = acpi_battery_get_status(battery);
392 if (result || !acpi_battery_present(battery)) 469 if (result)
393 return result; 470 return result;
394 if (saved_present != acpi_battery_present(battery) || 471 if (!acpi_battery_present(battery)) {
395 !battery->update_time) { 472 sysfs_remove_battery(battery);
396 battery->update_time = 0; 473 return 0;
397 result = acpi_battery_get_info(battery);
398 if (result)
399 return result;
400 if (battery->power_unit) {
401 battery->bat.properties = charge_battery_props;
402 battery->bat.num_properties =
403 ARRAY_SIZE(charge_battery_props);
404 } else {
405 battery->bat.properties = energy_battery_props;
406 battery->bat.num_properties =
407 ARRAY_SIZE(energy_battery_props);
408 }
409 acpi_battery_init_alarm(battery);
410 } 474 }
475 if (!battery->bat.dev)
476 sysfs_add_battery(battery);
411 return acpi_battery_get_state(battery); 477 return acpi_battery_get_state(battery);
412} 478}
413 479
@@ -415,7 +481,7 @@ static int acpi_battery_update(struct acpi_battery *battery)
415 FS Interface (/proc) 481 FS Interface (/proc)
416 -------------------------------------------------------------------------- */ 482 -------------------------------------------------------------------------- */
417 483
418#ifdef CONFIG_ACPI_PROCFS 484#ifdef CONFIG_ACPI_PROCFS_POWER
419static struct proc_dir_entry *acpi_battery_dir; 485static struct proc_dir_entry *acpi_battery_dir;
420 486
421static int acpi_battery_print_info(struct seq_file *seq, int result) 487static int acpi_battery_print_info(struct seq_file *seq, int result)
@@ -554,10 +620,6 @@ static ssize_t acpi_battery_write_alarm(struct file *file,
554 620
555 if (!battery || (count > sizeof(alarm_string) - 1)) 621 if (!battery || (count > sizeof(alarm_string) - 1))
556 return -EINVAL; 622 return -EINVAL;
557 if (result) {
558 result = -ENODEV;
559 goto end;
560 }
561 if (!acpi_battery_present(battery)) { 623 if (!acpi_battery_present(battery)) {
562 result = -ENODEV; 624 result = -ENODEV;
563 goto end; 625 goto end;
@@ -688,33 +750,6 @@ static void acpi_battery_remove_fs(struct acpi_device *device)
688 750
689#endif 751#endif
690 752
691static ssize_t acpi_battery_alarm_show(struct device *dev,
692 struct device_attribute *attr,
693 char *buf)
694{
695 struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
696 return sprintf(buf, "%d\n", battery->alarm * 1000);
697}
698
699static ssize_t acpi_battery_alarm_store(struct device *dev,
700 struct device_attribute *attr,
701 const char *buf, size_t count)
702{
703 unsigned long x;
704 struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
705 if (sscanf(buf, "%ld\n", &x) == 1)
706 battery->alarm = x/1000;
707 if (acpi_battery_present(battery))
708 acpi_battery_set_alarm(battery);
709 return count;
710}
711
712static struct device_attribute alarm_attr = {
713 .attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE},
714 .show = acpi_battery_alarm_show,
715 .store = acpi_battery_alarm_store,
716};
717
718/* -------------------------------------------------------------------------- 753/* --------------------------------------------------------------------------
719 Driver Interface 754 Driver Interface
720 -------------------------------------------------------------------------- */ 755 -------------------------------------------------------------------------- */
@@ -732,7 +767,9 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
732 acpi_bus_generate_netlink_event(device->pnp.device_class, 767 acpi_bus_generate_netlink_event(device->pnp.device_class,
733 device->dev.bus_id, event, 768 device->dev.bus_id, event,
734 acpi_battery_present(battery)); 769 acpi_battery_present(battery));
735 kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE); 770 /* acpi_batter_update could remove power_supply object */
771 if (battery->bat.dev)
772 kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE);
736} 773}
737 774
738static int acpi_battery_add(struct acpi_device *device) 775static int acpi_battery_add(struct acpi_device *device)
@@ -751,16 +788,11 @@ static int acpi_battery_add(struct acpi_device *device)
751 acpi_driver_data(device) = battery; 788 acpi_driver_data(device) = battery;
752 mutex_init(&battery->lock); 789 mutex_init(&battery->lock);
753 acpi_battery_update(battery); 790 acpi_battery_update(battery);
754#ifdef CONFIG_ACPI_PROCFS 791#ifdef CONFIG_ACPI_PROCFS_POWER
755 result = acpi_battery_add_fs(device); 792 result = acpi_battery_add_fs(device);
756 if (result) 793 if (result)
757 goto end; 794 goto end;
758#endif 795#endif
759 battery->bat.name = acpi_device_bid(device);
760 battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;
761 battery->bat.get_property = acpi_battery_get_property;
762 result = power_supply_register(&battery->device->dev, &battery->bat);
763 result = device_create_file(battery->bat.dev, &alarm_attr);
764 status = acpi_install_notify_handler(device->handle, 796 status = acpi_install_notify_handler(device->handle,
765 ACPI_ALL_NOTIFY, 797 ACPI_ALL_NOTIFY,
766 acpi_battery_notify, battery); 798 acpi_battery_notify, battery);
@@ -774,7 +806,7 @@ static int acpi_battery_add(struct acpi_device *device)
774 device->status.battery_present ? "present" : "absent"); 806 device->status.battery_present ? "present" : "absent");
775 end: 807 end:
776 if (result) { 808 if (result) {
777#ifdef CONFIG_ACPI_PROCFS 809#ifdef CONFIG_ACPI_PROCFS_POWER
778 acpi_battery_remove_fs(device); 810 acpi_battery_remove_fs(device);
779#endif 811#endif
780 kfree(battery); 812 kfree(battery);
@@ -793,13 +825,10 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
793 status = acpi_remove_notify_handler(device->handle, 825 status = acpi_remove_notify_handler(device->handle,
794 ACPI_ALL_NOTIFY, 826 ACPI_ALL_NOTIFY,
795 acpi_battery_notify); 827 acpi_battery_notify);
796#ifdef CONFIG_ACPI_PROCFS 828#ifdef CONFIG_ACPI_PROCFS_POWER
797 acpi_battery_remove_fs(device); 829 acpi_battery_remove_fs(device);
798#endif 830#endif
799 if (battery->bat.dev) { 831 sysfs_remove_battery(battery);
800 device_remove_file(battery->bat.dev, &alarm_attr);
801 power_supply_unregister(&battery->bat);
802 }
803 mutex_destroy(&battery->lock); 832 mutex_destroy(&battery->lock);
804 kfree(battery); 833 kfree(battery);
805 return 0; 834 return 0;
@@ -813,6 +842,7 @@ static int acpi_battery_resume(struct acpi_device *device)
813 return -EINVAL; 842 return -EINVAL;
814 battery = acpi_driver_data(device); 843 battery = acpi_driver_data(device);
815 battery->update_time = 0; 844 battery->update_time = 0;
845 acpi_battery_update(battery);
816 return 0; 846 return 0;
817} 847}
818 848
@@ -831,13 +861,13 @@ static int __init acpi_battery_init(void)
831{ 861{
832 if (acpi_disabled) 862 if (acpi_disabled)
833 return -ENODEV; 863 return -ENODEV;
834#ifdef CONFIG_ACPI_PROCFS 864#ifdef CONFIG_ACPI_PROCFS_POWER
835 acpi_battery_dir = acpi_lock_battery_dir(); 865 acpi_battery_dir = acpi_lock_battery_dir();
836 if (!acpi_battery_dir) 866 if (!acpi_battery_dir)
837 return -ENODEV; 867 return -ENODEV;
838#endif 868#endif
839 if (acpi_bus_register_driver(&acpi_battery_driver) < 0) { 869 if (acpi_bus_register_driver(&acpi_battery_driver) < 0) {
840#ifdef CONFIG_ACPI_PROCFS 870#ifdef CONFIG_ACPI_PROCFS_POWER
841 acpi_unlock_battery_dir(acpi_battery_dir); 871 acpi_unlock_battery_dir(acpi_battery_dir);
842#endif 872#endif
843 return -ENODEV; 873 return -ENODEV;
@@ -848,7 +878,7 @@ static int __init acpi_battery_init(void)
848static void __exit acpi_battery_exit(void) 878static void __exit acpi_battery_exit(void)
849{ 879{
850 acpi_bus_unregister_driver(&acpi_battery_driver); 880 acpi_bus_unregister_driver(&acpi_battery_driver);
851#ifdef CONFIG_ACPI_PROCFS 881#ifdef CONFIG_ACPI_PROCFS_POWER
852 acpi_unlock_battery_dir(acpi_battery_dir); 882 acpi_unlock_battery_dir(acpi_battery_dir);
853#endif 883#endif
854} 884}