diff options
Diffstat (limited to 'drivers/acpi/battery.c')
-rw-r--r-- | drivers/acpi/battery.c | 86 |
1 files changed, 54 insertions, 32 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 2c661353e8f2..7711d94a0409 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c | |||
@@ -55,6 +55,9 @@ | |||
55 | #define ACPI_BATTERY_NOTIFY_INFO 0x81 | 55 | #define ACPI_BATTERY_NOTIFY_INFO 0x81 |
56 | #define ACPI_BATTERY_NOTIFY_THRESHOLD 0x82 | 56 | #define ACPI_BATTERY_NOTIFY_THRESHOLD 0x82 |
57 | 57 | ||
58 | /* Battery power unit: 0 means mW, 1 means mA */ | ||
59 | #define ACPI_BATTERY_POWER_UNIT_MA 1 | ||
60 | |||
58 | #define _COMPONENT ACPI_BATTERY_COMPONENT | 61 | #define _COMPONENT ACPI_BATTERY_COMPONENT |
59 | 62 | ||
60 | ACPI_MODULE_NAME("battery"); | 63 | ACPI_MODULE_NAME("battery"); |
@@ -91,16 +94,12 @@ MODULE_DEVICE_TABLE(acpi, battery_device_ids); | |||
91 | enum { | 94 | enum { |
92 | ACPI_BATTERY_ALARM_PRESENT, | 95 | ACPI_BATTERY_ALARM_PRESENT, |
93 | ACPI_BATTERY_XINFO_PRESENT, | 96 | ACPI_BATTERY_XINFO_PRESENT, |
94 | /* For buggy DSDTs that report negative 16-bit values for either | ||
95 | * charging or discharging current and/or report 0 as 65536 | ||
96 | * due to bad math. | ||
97 | */ | ||
98 | ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, | ||
99 | ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, | 97 | ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, |
100 | }; | 98 | }; |
101 | 99 | ||
102 | struct acpi_battery { | 100 | struct acpi_battery { |
103 | struct mutex lock; | 101 | struct mutex lock; |
102 | struct mutex sysfs_lock; | ||
104 | struct power_supply bat; | 103 | struct power_supply bat; |
105 | struct acpi_device *device; | 104 | struct acpi_device *device; |
106 | struct notifier_block pm_nb; | 105 | struct notifier_block pm_nb; |
@@ -301,7 +300,8 @@ static enum power_supply_property energy_battery_props[] = { | |||
301 | #ifdef CONFIG_ACPI_PROCFS_POWER | 300 | #ifdef CONFIG_ACPI_PROCFS_POWER |
302 | inline char *acpi_battery_units(struct acpi_battery *battery) | 301 | inline char *acpi_battery_units(struct acpi_battery *battery) |
303 | { | 302 | { |
304 | return (battery->power_unit)?"mA":"mW"; | 303 | return (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) ? |
304 | "mA" : "mW"; | ||
305 | } | 305 | } |
306 | #endif | 306 | #endif |
307 | 307 | ||
@@ -461,9 +461,17 @@ static int acpi_battery_get_state(struct acpi_battery *battery) | |||
461 | battery->update_time = jiffies; | 461 | battery->update_time = jiffies; |
462 | kfree(buffer.pointer); | 462 | kfree(buffer.pointer); |
463 | 463 | ||
464 | if (test_bit(ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, &battery->flags) && | 464 | /* For buggy DSDTs that report negative 16-bit values for either |
465 | battery->rate_now != -1) | 465 | * charging or discharging current and/or report 0 as 65536 |
466 | * due to bad math. | ||
467 | */ | ||
468 | if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA && | ||
469 | battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN && | ||
470 | (s16)(battery->rate_now) < 0) { | ||
466 | battery->rate_now = abs((s16)battery->rate_now); | 471 | battery->rate_now = abs((s16)battery->rate_now); |
472 | printk_once(KERN_WARNING FW_BUG "battery: (dis)charge rate" | ||
473 | " invalid.\n"); | ||
474 | } | ||
467 | 475 | ||
468 | if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags) | 476 | if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags) |
469 | && battery->capacity_now >= 0 && battery->capacity_now <= 100) | 477 | && battery->capacity_now >= 0 && battery->capacity_now <= 100) |
@@ -544,7 +552,7 @@ static int sysfs_add_battery(struct acpi_battery *battery) | |||
544 | { | 552 | { |
545 | int result; | 553 | int result; |
546 | 554 | ||
547 | if (battery->power_unit) { | 555 | if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) { |
548 | battery->bat.properties = charge_battery_props; | 556 | battery->bat.properties = charge_battery_props; |
549 | battery->bat.num_properties = | 557 | battery->bat.num_properties = |
550 | ARRAY_SIZE(charge_battery_props); | 558 | ARRAY_SIZE(charge_battery_props); |
@@ -566,18 +574,16 @@ static int sysfs_add_battery(struct acpi_battery *battery) | |||
566 | 574 | ||
567 | static void sysfs_remove_battery(struct acpi_battery *battery) | 575 | static void sysfs_remove_battery(struct acpi_battery *battery) |
568 | { | 576 | { |
569 | if (!battery->bat.dev) | 577 | mutex_lock(&battery->sysfs_lock); |
578 | if (!battery->bat.dev) { | ||
579 | mutex_unlock(&battery->sysfs_lock); | ||
570 | return; | 580 | return; |
581 | } | ||
582 | |||
571 | device_remove_file(battery->bat.dev, &alarm_attr); | 583 | device_remove_file(battery->bat.dev, &alarm_attr); |
572 | power_supply_unregister(&battery->bat); | 584 | power_supply_unregister(&battery->bat); |
573 | battery->bat.dev = NULL; | 585 | battery->bat.dev = NULL; |
574 | } | 586 | mutex_unlock(&battery->sysfs_lock); |
575 | |||
576 | static void acpi_battery_quirks(struct acpi_battery *battery) | ||
577 | { | ||
578 | if (dmi_name_in_vendors("Acer") && battery->power_unit) { | ||
579 | set_bit(ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, &battery->flags); | ||
580 | } | ||
581 | } | 587 | } |
582 | 588 | ||
583 | /* | 589 | /* |
@@ -592,7 +598,7 @@ static void acpi_battery_quirks(struct acpi_battery *battery) | |||
592 | * | 598 | * |
593 | * Handle this correctly so that they won't break userspace. | 599 | * Handle this correctly so that they won't break userspace. |
594 | */ | 600 | */ |
595 | static void acpi_battery_quirks2(struct acpi_battery *battery) | 601 | static void acpi_battery_quirks(struct acpi_battery *battery) |
596 | { | 602 | { |
597 | if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)) | 603 | if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)) |
598 | return ; | 604 | return ; |
@@ -623,13 +629,15 @@ static int acpi_battery_update(struct acpi_battery *battery) | |||
623 | result = acpi_battery_get_info(battery); | 629 | result = acpi_battery_get_info(battery); |
624 | if (result) | 630 | if (result) |
625 | return result; | 631 | return result; |
626 | acpi_battery_quirks(battery); | ||
627 | acpi_battery_init_alarm(battery); | 632 | acpi_battery_init_alarm(battery); |
628 | } | 633 | } |
629 | if (!battery->bat.dev) | 634 | if (!battery->bat.dev) { |
630 | sysfs_add_battery(battery); | 635 | result = sysfs_add_battery(battery); |
636 | if (result) | ||
637 | return result; | ||
638 | } | ||
631 | result = acpi_battery_get_state(battery); | 639 | result = acpi_battery_get_state(battery); |
632 | acpi_battery_quirks2(battery); | 640 | acpi_battery_quirks(battery); |
633 | return result; | 641 | return result; |
634 | } | 642 | } |
635 | 643 | ||
@@ -863,7 +871,7 @@ DECLARE_FILE_FUNCTIONS(alarm); | |||
863 | }, \ | 871 | }, \ |
864 | } | 872 | } |
865 | 873 | ||
866 | static struct battery_file { | 874 | static const struct battery_file { |
867 | struct file_operations ops; | 875 | struct file_operations ops; |
868 | mode_t mode; | 876 | mode_t mode; |
869 | const char *name; | 877 | const char *name; |
@@ -948,9 +956,12 @@ static int battery_notify(struct notifier_block *nb, | |||
948 | struct acpi_battery *battery = container_of(nb, struct acpi_battery, | 956 | struct acpi_battery *battery = container_of(nb, struct acpi_battery, |
949 | pm_nb); | 957 | pm_nb); |
950 | switch (mode) { | 958 | switch (mode) { |
959 | case PM_POST_HIBERNATION: | ||
951 | case PM_POST_SUSPEND: | 960 | case PM_POST_SUSPEND: |
952 | sysfs_remove_battery(battery); | 961 | if (battery->bat.dev) { |
953 | sysfs_add_battery(battery); | 962 | sysfs_remove_battery(battery); |
963 | sysfs_add_battery(battery); | ||
964 | } | ||
954 | break; | 965 | break; |
955 | } | 966 | } |
956 | 967 | ||
@@ -972,28 +983,38 @@ static int acpi_battery_add(struct acpi_device *device) | |||
972 | strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); | 983 | strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); |
973 | device->driver_data = battery; | 984 | device->driver_data = battery; |
974 | mutex_init(&battery->lock); | 985 | mutex_init(&battery->lock); |
986 | mutex_init(&battery->sysfs_lock); | ||
975 | if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle, | 987 | if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle, |
976 | "_BIX", &handle))) | 988 | "_BIX", &handle))) |
977 | set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); | 989 | set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); |
978 | acpi_battery_update(battery); | 990 | result = acpi_battery_update(battery); |
991 | if (result) | ||
992 | goto fail; | ||
979 | #ifdef CONFIG_ACPI_PROCFS_POWER | 993 | #ifdef CONFIG_ACPI_PROCFS_POWER |
980 | result = acpi_battery_add_fs(device); | 994 | result = acpi_battery_add_fs(device); |
981 | #endif | 995 | #endif |
982 | if (!result) { | 996 | if (result) { |
983 | printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", | ||
984 | ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), | ||
985 | device->status.battery_present ? "present" : "absent"); | ||
986 | } else { | ||
987 | #ifdef CONFIG_ACPI_PROCFS_POWER | 997 | #ifdef CONFIG_ACPI_PROCFS_POWER |
988 | acpi_battery_remove_fs(device); | 998 | acpi_battery_remove_fs(device); |
989 | #endif | 999 | #endif |
990 | kfree(battery); | 1000 | goto fail; |
991 | } | 1001 | } |
992 | 1002 | ||
1003 | printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", | ||
1004 | ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), | ||
1005 | device->status.battery_present ? "present" : "absent"); | ||
1006 | |||
993 | battery->pm_nb.notifier_call = battery_notify; | 1007 | battery->pm_nb.notifier_call = battery_notify; |
994 | register_pm_notifier(&battery->pm_nb); | 1008 | register_pm_notifier(&battery->pm_nb); |
995 | 1009 | ||
996 | return result; | 1010 | return result; |
1011 | |||
1012 | fail: | ||
1013 | sysfs_remove_battery(battery); | ||
1014 | mutex_destroy(&battery->lock); | ||
1015 | mutex_destroy(&battery->sysfs_lock); | ||
1016 | kfree(battery); | ||
1017 | return result; | ||
997 | } | 1018 | } |
998 | 1019 | ||
999 | static int acpi_battery_remove(struct acpi_device *device, int type) | 1020 | static int acpi_battery_remove(struct acpi_device *device, int type) |
@@ -1009,6 +1030,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type) | |||
1009 | #endif | 1030 | #endif |
1010 | sysfs_remove_battery(battery); | 1031 | sysfs_remove_battery(battery); |
1011 | mutex_destroy(&battery->lock); | 1032 | mutex_destroy(&battery->lock); |
1033 | mutex_destroy(&battery->sysfs_lock); | ||
1012 | kfree(battery); | 1034 | kfree(battery); |
1013 | return 0; | 1035 | return 0; |
1014 | } | 1036 | } |