diff options
Diffstat (limited to 'drivers/acpi/battery.c')
-rw-r--r-- | drivers/acpi/battery.c | 192 |
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; | |||
63 | module_param(cache_time, uint, 0644); | 63 | module_param(cache_time, uint, 0644); |
64 | MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); | 64 | MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); |
65 | 65 | ||
66 | #ifdef CONFIG_ACPI_PROCFS | 66 | #ifdef CONFIG_ACPI_PROCFS_POWER |
67 | extern struct proc_dir_entry *acpi_lock_battery_dir(void); | 67 | extern struct proc_dir_entry *acpi_lock_battery_dir(void); |
68 | extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); | 68 | extern 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 | ||
135 | static int acpi_battery_get_state(struct acpi_battery *battery); | ||
136 | |||
133 | static int acpi_battery_get_property(struct power_supply *psy, | 137 | static 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 |
219 | inline char *acpi_battery_units(struct acpi_battery *battery) | 227 | inline 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 | ||
401 | static 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 | |||
409 | static 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 | |||
422 | static 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 | |||
428 | static 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 | |||
457 | static 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 | |||
388 | static int acpi_battery_update(struct acpi_battery *battery) | 466 | static 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 |
419 | static struct proc_dir_entry *acpi_battery_dir; | 485 | static struct proc_dir_entry *acpi_battery_dir; |
420 | 486 | ||
421 | static int acpi_battery_print_info(struct seq_file *seq, int result) | 487 | static 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 | ||
691 | static 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 | |||
699 | static 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 | |||
712 | static 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 | ||
738 | static int acpi_battery_add(struct acpi_device *device) | 775 | static 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) | |||
848 | static void __exit acpi_battery_exit(void) | 878 | static 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 | } |