diff options
Diffstat (limited to 'drivers/acpi/battery.c')
-rw-r--r-- | drivers/acpi/battery.c | 93 |
1 files changed, 72 insertions, 21 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 58d2c91ba62b..3026e3fa83ef 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/jiffies.h> | 32 | #include <linux/jiffies.h> |
33 | #include <linux/async.h> | 33 | #include <linux/async.h> |
34 | #include <linux/dmi.h> | 34 | #include <linux/dmi.h> |
35 | #include <linux/slab.h> | ||
35 | 36 | ||
36 | #ifdef CONFIG_ACPI_PROCFS_POWER | 37 | #ifdef CONFIG_ACPI_PROCFS_POWER |
37 | #include <linux/proc_fs.h> | 38 | #include <linux/proc_fs.h> |
@@ -54,6 +55,7 @@ | |||
54 | #define ACPI_BATTERY_DEVICE_NAME "Battery" | 55 | #define ACPI_BATTERY_DEVICE_NAME "Battery" |
55 | #define ACPI_BATTERY_NOTIFY_STATUS 0x80 | 56 | #define ACPI_BATTERY_NOTIFY_STATUS 0x80 |
56 | #define ACPI_BATTERY_NOTIFY_INFO 0x81 | 57 | #define ACPI_BATTERY_NOTIFY_INFO 0x81 |
58 | #define ACPI_BATTERY_NOTIFY_THRESHOLD 0x82 | ||
57 | 59 | ||
58 | #define _COMPONENT ACPI_BATTERY_COMPONENT | 60 | #define _COMPONENT ACPI_BATTERY_COMPONENT |
59 | 61 | ||
@@ -88,10 +90,15 @@ static const struct acpi_device_id battery_device_ids[] = { | |||
88 | 90 | ||
89 | MODULE_DEVICE_TABLE(acpi, battery_device_ids); | 91 | MODULE_DEVICE_TABLE(acpi, battery_device_ids); |
90 | 92 | ||
91 | /* For buggy DSDTs that report negative 16-bit values for either charging | 93 | enum { |
92 | * or discharging current and/or report 0 as 65536 due to bad math. | 94 | ACPI_BATTERY_ALARM_PRESENT, |
93 | */ | 95 | ACPI_BATTERY_XINFO_PRESENT, |
94 | #define QUIRK_SIGNED16_CURRENT 0x0001 | 96 | /* For buggy DSDTs that report negative 16-bit values for either |
97 | * charging or discharging current and/or report 0 as 65536 | ||
98 | * due to bad math. | ||
99 | */ | ||
100 | ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, | ||
101 | }; | ||
95 | 102 | ||
96 | struct acpi_battery { | 103 | struct acpi_battery { |
97 | struct mutex lock; | 104 | struct mutex lock; |
@@ -109,6 +116,12 @@ struct acpi_battery { | |||
109 | int design_voltage; | 116 | int design_voltage; |
110 | int design_capacity_warning; | 117 | int design_capacity_warning; |
111 | int design_capacity_low; | 118 | int design_capacity_low; |
119 | int cycle_count; | ||
120 | int measurement_accuracy; | ||
121 | int max_sampling_time; | ||
122 | int min_sampling_time; | ||
123 | int max_averaging_interval; | ||
124 | int min_averaging_interval; | ||
112 | int capacity_granularity_1; | 125 | int capacity_granularity_1; |
113 | int capacity_granularity_2; | 126 | int capacity_granularity_2; |
114 | int alarm; | 127 | int alarm; |
@@ -118,8 +131,7 @@ struct acpi_battery { | |||
118 | char oem_info[32]; | 131 | char oem_info[32]; |
119 | int state; | 132 | int state; |
120 | int power_unit; | 133 | int power_unit; |
121 | u8 alarm_present; | 134 | unsigned long flags; |
122 | long quirks; | ||
123 | }; | 135 | }; |
124 | 136 | ||
125 | #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); | 137 | #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); |
@@ -198,6 +210,9 @@ static int acpi_battery_get_property(struct power_supply *psy, | |||
198 | case POWER_SUPPLY_PROP_TECHNOLOGY: | 210 | case POWER_SUPPLY_PROP_TECHNOLOGY: |
199 | val->intval = acpi_battery_technology(battery); | 211 | val->intval = acpi_battery_technology(battery); |
200 | break; | 212 | break; |
213 | case POWER_SUPPLY_PROP_CYCLE_COUNT: | ||
214 | val->intval = battery->cycle_count; | ||
215 | break; | ||
201 | case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: | 216 | case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: |
202 | val->intval = battery->design_voltage * 1000; | 217 | val->intval = battery->design_voltage * 1000; |
203 | break; | 218 | break; |
@@ -239,6 +254,7 @@ static enum power_supply_property charge_battery_props[] = { | |||
239 | POWER_SUPPLY_PROP_STATUS, | 254 | POWER_SUPPLY_PROP_STATUS, |
240 | POWER_SUPPLY_PROP_PRESENT, | 255 | POWER_SUPPLY_PROP_PRESENT, |
241 | POWER_SUPPLY_PROP_TECHNOLOGY, | 256 | POWER_SUPPLY_PROP_TECHNOLOGY, |
257 | POWER_SUPPLY_PROP_CYCLE_COUNT, | ||
242 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, | 258 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, |
243 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | 259 | POWER_SUPPLY_PROP_VOLTAGE_NOW, |
244 | POWER_SUPPLY_PROP_CURRENT_NOW, | 260 | POWER_SUPPLY_PROP_CURRENT_NOW, |
@@ -254,6 +270,7 @@ static enum power_supply_property energy_battery_props[] = { | |||
254 | POWER_SUPPLY_PROP_STATUS, | 270 | POWER_SUPPLY_PROP_STATUS, |
255 | POWER_SUPPLY_PROP_PRESENT, | 271 | POWER_SUPPLY_PROP_PRESENT, |
256 | POWER_SUPPLY_PROP_TECHNOLOGY, | 272 | POWER_SUPPLY_PROP_TECHNOLOGY, |
273 | POWER_SUPPLY_PROP_CYCLE_COUNT, | ||
257 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, | 274 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, |
258 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | 275 | POWER_SUPPLY_PROP_VOLTAGE_NOW, |
259 | POWER_SUPPLY_PROP_CURRENT_NOW, | 276 | POWER_SUPPLY_PROP_CURRENT_NOW, |
@@ -305,6 +322,28 @@ static struct acpi_offsets info_offsets[] = { | |||
305 | {offsetof(struct acpi_battery, oem_info), 1}, | 322 | {offsetof(struct acpi_battery, oem_info), 1}, |
306 | }; | 323 | }; |
307 | 324 | ||
325 | static struct acpi_offsets extended_info_offsets[] = { | ||
326 | {offsetof(struct acpi_battery, power_unit), 0}, | ||
327 | {offsetof(struct acpi_battery, design_capacity), 0}, | ||
328 | {offsetof(struct acpi_battery, full_charge_capacity), 0}, | ||
329 | {offsetof(struct acpi_battery, technology), 0}, | ||
330 | {offsetof(struct acpi_battery, design_voltage), 0}, | ||
331 | {offsetof(struct acpi_battery, design_capacity_warning), 0}, | ||
332 | {offsetof(struct acpi_battery, design_capacity_low), 0}, | ||
333 | {offsetof(struct acpi_battery, cycle_count), 0}, | ||
334 | {offsetof(struct acpi_battery, measurement_accuracy), 0}, | ||
335 | {offsetof(struct acpi_battery, max_sampling_time), 0}, | ||
336 | {offsetof(struct acpi_battery, min_sampling_time), 0}, | ||
337 | {offsetof(struct acpi_battery, max_averaging_interval), 0}, | ||
338 | {offsetof(struct acpi_battery, min_averaging_interval), 0}, | ||
339 | {offsetof(struct acpi_battery, capacity_granularity_1), 0}, | ||
340 | {offsetof(struct acpi_battery, capacity_granularity_2), 0}, | ||
341 | {offsetof(struct acpi_battery, model_number), 1}, | ||
342 | {offsetof(struct acpi_battery, serial_number), 1}, | ||
343 | {offsetof(struct acpi_battery, type), 1}, | ||
344 | {offsetof(struct acpi_battery, oem_info), 1}, | ||
345 | }; | ||
346 | |||
308 | static int extract_package(struct acpi_battery *battery, | 347 | static int extract_package(struct acpi_battery *battery, |
309 | union acpi_object *package, | 348 | union acpi_object *package, |
310 | struct acpi_offsets *offsets, int num) | 349 | struct acpi_offsets *offsets, int num) |
@@ -350,22 +389,29 @@ static int acpi_battery_get_info(struct acpi_battery *battery) | |||
350 | { | 389 | { |
351 | int result = -EFAULT; | 390 | int result = -EFAULT; |
352 | acpi_status status = 0; | 391 | acpi_status status = 0; |
392 | char *name = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags)? | ||
393 | "_BIX" : "_BIF"; | ||
394 | |||
353 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 395 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
354 | 396 | ||
355 | if (!acpi_battery_present(battery)) | 397 | if (!acpi_battery_present(battery)) |
356 | return 0; | 398 | return 0; |
357 | mutex_lock(&battery->lock); | 399 | mutex_lock(&battery->lock); |
358 | status = acpi_evaluate_object(battery->device->handle, "_BIF", | 400 | status = acpi_evaluate_object(battery->device->handle, name, |
359 | NULL, &buffer); | 401 | NULL, &buffer); |
360 | mutex_unlock(&battery->lock); | 402 | mutex_unlock(&battery->lock); |
361 | 403 | ||
362 | if (ACPI_FAILURE(status)) { | 404 | if (ACPI_FAILURE(status)) { |
363 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF")); | 405 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s", name)); |
364 | return -ENODEV; | 406 | return -ENODEV; |
365 | } | 407 | } |
366 | 408 | if (test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags)) | |
367 | result = extract_package(battery, buffer.pointer, | 409 | result = extract_package(battery, buffer.pointer, |
368 | info_offsets, ARRAY_SIZE(info_offsets)); | 410 | extended_info_offsets, |
411 | ARRAY_SIZE(extended_info_offsets)); | ||
412 | else | ||
413 | result = extract_package(battery, buffer.pointer, | ||
414 | info_offsets, ARRAY_SIZE(info_offsets)); | ||
369 | kfree(buffer.pointer); | 415 | kfree(buffer.pointer); |
370 | return result; | 416 | return result; |
371 | } | 417 | } |
@@ -399,7 +445,7 @@ static int acpi_battery_get_state(struct acpi_battery *battery) | |||
399 | battery->update_time = jiffies; | 445 | battery->update_time = jiffies; |
400 | kfree(buffer.pointer); | 446 | kfree(buffer.pointer); |
401 | 447 | ||
402 | if ((battery->quirks & QUIRK_SIGNED16_CURRENT) && | 448 | if (test_bit(ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, &battery->flags) && |
403 | battery->rate_now != -1) | 449 | battery->rate_now != -1) |
404 | battery->rate_now = abs((s16)battery->rate_now); | 450 | battery->rate_now = abs((s16)battery->rate_now); |
405 | 451 | ||
@@ -412,7 +458,8 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery) | |||
412 | union acpi_object arg0 = { .type = ACPI_TYPE_INTEGER }; | 458 | union acpi_object arg0 = { .type = ACPI_TYPE_INTEGER }; |
413 | struct acpi_object_list arg_list = { 1, &arg0 }; | 459 | struct acpi_object_list arg_list = { 1, &arg0 }; |
414 | 460 | ||
415 | if (!acpi_battery_present(battery)|| !battery->alarm_present) | 461 | if (!acpi_battery_present(battery) || |
462 | !test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags)) | ||
416 | return -ENODEV; | 463 | return -ENODEV; |
417 | 464 | ||
418 | arg0.integer.value = battery->alarm; | 465 | arg0.integer.value = battery->alarm; |
@@ -437,10 +484,10 @@ static int acpi_battery_init_alarm(struct acpi_battery *battery) | |||
437 | /* See if alarms are supported, and if so, set default */ | 484 | /* See if alarms are supported, and if so, set default */ |
438 | status = acpi_get_handle(battery->device->handle, "_BTP", &handle); | 485 | status = acpi_get_handle(battery->device->handle, "_BTP", &handle); |
439 | if (ACPI_FAILURE(status)) { | 486 | if (ACPI_FAILURE(status)) { |
440 | battery->alarm_present = 0; | 487 | clear_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags); |
441 | return 0; | 488 | return 0; |
442 | } | 489 | } |
443 | battery->alarm_present = 1; | 490 | set_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags); |
444 | if (!battery->alarm) | 491 | if (!battery->alarm) |
445 | battery->alarm = battery->design_capacity_warning; | 492 | battery->alarm = battery->design_capacity_warning; |
446 | return acpi_battery_set_alarm(battery); | 493 | return acpi_battery_set_alarm(battery); |
@@ -510,9 +557,8 @@ static void sysfs_remove_battery(struct acpi_battery *battery) | |||
510 | 557 | ||
511 | static void acpi_battery_quirks(struct acpi_battery *battery) | 558 | static void acpi_battery_quirks(struct acpi_battery *battery) |
512 | { | 559 | { |
513 | battery->quirks = 0; | ||
514 | if (dmi_name_in_vendors("Acer") && battery->power_unit) { | 560 | if (dmi_name_in_vendors("Acer") && battery->power_unit) { |
515 | battery->quirks |= QUIRK_SIGNED16_CURRENT; | 561 | set_bit(ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, &battery->flags); |
516 | } | 562 | } |
517 | } | 563 | } |
518 | 564 | ||
@@ -522,13 +568,13 @@ static int acpi_battery_update(struct acpi_battery *battery) | |||
522 | result = acpi_battery_get_status(battery); | 568 | result = acpi_battery_get_status(battery); |
523 | if (result) | 569 | if (result) |
524 | return result; | 570 | return result; |
525 | #ifdef CONFIG_ACPI_SYSFS_POWER | ||
526 | if (!acpi_battery_present(battery)) { | 571 | if (!acpi_battery_present(battery)) { |
572 | #ifdef CONFIG_ACPI_SYSFS_POWER | ||
527 | sysfs_remove_battery(battery); | 573 | sysfs_remove_battery(battery); |
574 | #endif | ||
528 | battery->update_time = 0; | 575 | battery->update_time = 0; |
529 | return 0; | 576 | return 0; |
530 | } | 577 | } |
531 | #endif | ||
532 | if (!battery->update_time || | 578 | if (!battery->update_time || |
533 | old_present != acpi_battery_present(battery)) { | 579 | old_present != acpi_battery_present(battery)) { |
534 | result = acpi_battery_get_info(battery); | 580 | result = acpi_battery_get_info(battery); |
@@ -590,6 +636,7 @@ static int acpi_battery_print_info(struct seq_file *seq, int result) | |||
590 | seq_printf(seq, "design capacity low: %d %sh\n", | 636 | seq_printf(seq, "design capacity low: %d %sh\n", |
591 | battery->design_capacity_low, | 637 | battery->design_capacity_low, |
592 | acpi_battery_units(battery)); | 638 | acpi_battery_units(battery)); |
639 | seq_printf(seq, "cycle count: %i\n", battery->cycle_count); | ||
593 | seq_printf(seq, "capacity granularity 1: %d %sh\n", | 640 | seq_printf(seq, "capacity granularity 1: %d %sh\n", |
594 | battery->capacity_granularity_1, | 641 | battery->capacity_granularity_1, |
595 | acpi_battery_units(battery)); | 642 | acpi_battery_units(battery)); |
@@ -833,7 +880,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event) | |||
833 | #ifdef CONFIG_ACPI_SYSFS_POWER | 880 | #ifdef CONFIG_ACPI_SYSFS_POWER |
834 | /* acpi_battery_update could remove power_supply object */ | 881 | /* acpi_battery_update could remove power_supply object */ |
835 | if (battery->bat.dev) | 882 | if (battery->bat.dev) |
836 | kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE); | 883 | power_supply_changed(&battery->bat); |
837 | #endif | 884 | #endif |
838 | } | 885 | } |
839 | 886 | ||
@@ -841,6 +888,7 @@ static int acpi_battery_add(struct acpi_device *device) | |||
841 | { | 888 | { |
842 | int result = 0; | 889 | int result = 0; |
843 | struct acpi_battery *battery = NULL; | 890 | struct acpi_battery *battery = NULL; |
891 | acpi_handle handle; | ||
844 | if (!device) | 892 | if (!device) |
845 | return -EINVAL; | 893 | return -EINVAL; |
846 | battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); | 894 | battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); |
@@ -851,6 +899,9 @@ static int acpi_battery_add(struct acpi_device *device) | |||
851 | strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); | 899 | strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); |
852 | device->driver_data = battery; | 900 | device->driver_data = battery; |
853 | mutex_init(&battery->lock); | 901 | mutex_init(&battery->lock); |
902 | if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle, | ||
903 | "_BIX", &handle))) | ||
904 | set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); | ||
854 | acpi_battery_update(battery); | 905 | acpi_battery_update(battery); |
855 | #ifdef CONFIG_ACPI_PROCFS_POWER | 906 | #ifdef CONFIG_ACPI_PROCFS_POWER |
856 | result = acpi_battery_add_fs(device); | 907 | result = acpi_battery_add_fs(device); |