diff options
Diffstat (limited to 'drivers/acpi/battery.c')
| -rw-r--r-- | drivers/acpi/battery.c | 88 |
1 files changed, 55 insertions, 33 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index fcc13ac0aa1..7711d94a040 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; |
| @@ -132,7 +131,7 @@ struct acpi_battery { | |||
| 132 | unsigned long flags; | 131 | unsigned long flags; |
| 133 | }; | 132 | }; |
| 134 | 133 | ||
| 135 | #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); | 134 | #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat) |
| 136 | 135 | ||
| 137 | inline int acpi_battery_present(struct acpi_battery *battery) | 136 | inline int acpi_battery_present(struct acpi_battery *battery) |
| 138 | { | 137 | { |
| @@ -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 | } |
