diff options
Diffstat (limited to 'drivers/acpi/battery.c')
-rw-r--r-- | drivers/acpi/battery.c | 164 |
1 files changed, 95 insertions, 69 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 681e26b56b11..c2ce0ad21693 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c | |||
@@ -125,11 +125,15 @@ 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_update(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) |
@@ -139,6 +143,7 @@ static int acpi_battery_get_property(struct power_supply *psy, | |||
139 | if ((!acpi_battery_present(battery)) && | 143 | if ((!acpi_battery_present(battery)) && |
140 | psp != POWER_SUPPLY_PROP_PRESENT) | 144 | psp != POWER_SUPPLY_PROP_PRESENT) |
141 | return -ENODEV; | 145 | return -ENODEV; |
146 | acpi_battery_update(battery); | ||
142 | switch (psp) { | 147 | switch (psp) { |
143 | case POWER_SUPPLY_PROP_STATUS: | 148 | case POWER_SUPPLY_PROP_STATUS: |
144 | if (battery->state & 0x01) | 149 | if (battery->state & 0x01) |
@@ -257,7 +262,7 @@ static int extract_package(struct acpi_battery *battery, | |||
257 | union acpi_object *package, | 262 | union acpi_object *package, |
258 | struct acpi_offsets *offsets, int num) | 263 | struct acpi_offsets *offsets, int num) |
259 | { | 264 | { |
260 | int i, *x; | 265 | int i; |
261 | union acpi_object *element; | 266 | union acpi_object *element; |
262 | if (package->type != ACPI_TYPE_PACKAGE) | 267 | if (package->type != ACPI_TYPE_PACKAGE) |
263 | return -EFAULT; | 268 | return -EFAULT; |
@@ -266,16 +271,21 @@ static int extract_package(struct acpi_battery *battery, | |||
266 | return -EFAULT; | 271 | return -EFAULT; |
267 | element = &package->package.elements[i]; | 272 | element = &package->package.elements[i]; |
268 | if (offsets[i].mode) { | 273 | if (offsets[i].mode) { |
269 | if (element->type != ACPI_TYPE_STRING && | 274 | u8 *ptr = (u8 *)battery + offsets[i].offset; |
270 | element->type != ACPI_TYPE_BUFFER) | 275 | if (element->type == ACPI_TYPE_STRING || |
271 | return -EFAULT; | 276 | element->type == ACPI_TYPE_BUFFER) |
272 | strncpy((u8 *)battery + offsets[i].offset, | 277 | strncpy(ptr, element->string.pointer, 32); |
273 | element->string.pointer, 32); | 278 | else if (element->type == ACPI_TYPE_INTEGER) { |
279 | strncpy(ptr, (u8 *)&element->integer.value, | ||
280 | sizeof(acpi_integer)); | ||
281 | ptr[sizeof(acpi_integer)] = 0; | ||
282 | } else return -EFAULT; | ||
274 | } else { | 283 | } else { |
275 | if (element->type != ACPI_TYPE_INTEGER) | 284 | if (element->type == ACPI_TYPE_INTEGER) { |
276 | return -EFAULT; | 285 | int *x = (int *)((u8 *)battery + |
277 | x = (int *)((u8 *)battery + offsets[i].offset); | 286 | offsets[i].offset); |
278 | *x = element->integer.value; | 287 | *x = element->integer.value; |
288 | } else return -EFAULT; | ||
279 | } | 289 | } |
280 | } | 290 | } |
281 | return 0; | 291 | return 0; |
@@ -385,29 +395,81 @@ static int acpi_battery_init_alarm(struct acpi_battery *battery) | |||
385 | return acpi_battery_set_alarm(battery); | 395 | return acpi_battery_set_alarm(battery); |
386 | } | 396 | } |
387 | 397 | ||
398 | static ssize_t acpi_battery_alarm_show(struct device *dev, | ||
399 | struct device_attribute *attr, | ||
400 | char *buf) | ||
401 | { | ||
402 | struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); | ||
403 | return sprintf(buf, "%d\n", battery->alarm * 1000); | ||
404 | } | ||
405 | |||
406 | static ssize_t acpi_battery_alarm_store(struct device *dev, | ||
407 | struct device_attribute *attr, | ||
408 | const char *buf, size_t count) | ||
409 | { | ||
410 | unsigned long x; | ||
411 | struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); | ||
412 | if (sscanf(buf, "%ld\n", &x) == 1) | ||
413 | battery->alarm = x/1000; | ||
414 | if (acpi_battery_present(battery)) | ||
415 | acpi_battery_set_alarm(battery); | ||
416 | return count; | ||
417 | } | ||
418 | |||
419 | static struct device_attribute alarm_attr = { | ||
420 | .attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE}, | ||
421 | .show = acpi_battery_alarm_show, | ||
422 | .store = acpi_battery_alarm_store, | ||
423 | }; | ||
424 | |||
425 | static int sysfs_add_battery(struct acpi_battery *battery) | ||
426 | { | ||
427 | int result; | ||
428 | |||
429 | battery->update_time = 0; | ||
430 | result = acpi_battery_get_info(battery); | ||
431 | acpi_battery_init_alarm(battery); | ||
432 | if (result) | ||
433 | return result; | ||
434 | if (battery->power_unit) { | ||
435 | battery->bat.properties = charge_battery_props; | ||
436 | battery->bat.num_properties = | ||
437 | ARRAY_SIZE(charge_battery_props); | ||
438 | } else { | ||
439 | battery->bat.properties = energy_battery_props; | ||
440 | battery->bat.num_properties = | ||
441 | ARRAY_SIZE(energy_battery_props); | ||
442 | } | ||
443 | |||
444 | battery->bat.name = acpi_device_bid(battery->device); | ||
445 | battery->bat.type = POWER_SUPPLY_TYPE_BATTERY; | ||
446 | battery->bat.get_property = acpi_battery_get_property; | ||
447 | |||
448 | result = power_supply_register(&battery->device->dev, &battery->bat); | ||
449 | if (result) | ||
450 | return result; | ||
451 | return device_create_file(battery->bat.dev, &alarm_attr); | ||
452 | } | ||
453 | |||
454 | static void sysfs_remove_battery(struct acpi_battery *battery) | ||
455 | { | ||
456 | if (!battery->bat.dev) | ||
457 | return; | ||
458 | device_remove_file(battery->bat.dev, &alarm_attr); | ||
459 | power_supply_unregister(&battery->bat); | ||
460 | } | ||
461 | |||
388 | static int acpi_battery_update(struct acpi_battery *battery) | 462 | static int acpi_battery_update(struct acpi_battery *battery) |
389 | { | 463 | { |
390 | int saved_present = acpi_battery_present(battery); | ||
391 | int result = acpi_battery_get_status(battery); | 464 | int result = acpi_battery_get_status(battery); |
392 | if (result || !acpi_battery_present(battery)) | 465 | if (result) |
393 | return result; | 466 | return result; |
394 | if (saved_present != acpi_battery_present(battery) || | 467 | if (!acpi_battery_present(battery)) { |
395 | !battery->update_time) { | 468 | sysfs_remove_battery(battery); |
396 | battery->update_time = 0; | 469 | 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 | } | 470 | } |
471 | if (!battery->bat.dev) | ||
472 | sysfs_add_battery(battery); | ||
411 | return acpi_battery_get_state(battery); | 473 | return acpi_battery_get_state(battery); |
412 | } | 474 | } |
413 | 475 | ||
@@ -554,10 +616,6 @@ static ssize_t acpi_battery_write_alarm(struct file *file, | |||
554 | 616 | ||
555 | if (!battery || (count > sizeof(alarm_string) - 1)) | 617 | if (!battery || (count > sizeof(alarm_string) - 1)) |
556 | return -EINVAL; | 618 | return -EINVAL; |
557 | if (result) { | ||
558 | result = -ENODEV; | ||
559 | goto end; | ||
560 | } | ||
561 | if (!acpi_battery_present(battery)) { | 619 | if (!acpi_battery_present(battery)) { |
562 | result = -ENODEV; | 620 | result = -ENODEV; |
563 | goto end; | 621 | goto end; |
@@ -688,33 +746,6 @@ static void acpi_battery_remove_fs(struct acpi_device *device) | |||
688 | 746 | ||
689 | #endif | 747 | #endif |
690 | 748 | ||
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 | /* -------------------------------------------------------------------------- | 749 | /* -------------------------------------------------------------------------- |
719 | Driver Interface | 750 | Driver Interface |
720 | -------------------------------------------------------------------------- */ | 751 | -------------------------------------------------------------------------- */ |
@@ -732,7 +763,9 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) | |||
732 | acpi_bus_generate_netlink_event(device->pnp.device_class, | 763 | acpi_bus_generate_netlink_event(device->pnp.device_class, |
733 | device->dev.bus_id, event, | 764 | device->dev.bus_id, event, |
734 | acpi_battery_present(battery)); | 765 | acpi_battery_present(battery)); |
735 | kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE); | 766 | /* acpi_batter_update could remove power_supply object */ |
767 | if (battery->bat.dev) | ||
768 | kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE); | ||
736 | } | 769 | } |
737 | 770 | ||
738 | static int acpi_battery_add(struct acpi_device *device) | 771 | static int acpi_battery_add(struct acpi_device *device) |
@@ -756,11 +789,6 @@ static int acpi_battery_add(struct acpi_device *device) | |||
756 | if (result) | 789 | if (result) |
757 | goto end; | 790 | goto end; |
758 | #endif | 791 | #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, | 792 | status = acpi_install_notify_handler(device->handle, |
765 | ACPI_ALL_NOTIFY, | 793 | ACPI_ALL_NOTIFY, |
766 | acpi_battery_notify, battery); | 794 | acpi_battery_notify, battery); |
@@ -796,10 +824,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type) | |||
796 | #ifdef CONFIG_ACPI_PROCFS | 824 | #ifdef CONFIG_ACPI_PROCFS |
797 | acpi_battery_remove_fs(device); | 825 | acpi_battery_remove_fs(device); |
798 | #endif | 826 | #endif |
799 | if (battery->bat.dev) { | 827 | 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); | 828 | mutex_destroy(&battery->lock); |
804 | kfree(battery); | 829 | kfree(battery); |
805 | return 0; | 830 | return 0; |
@@ -813,6 +838,7 @@ static int acpi_battery_resume(struct acpi_device *device) | |||
813 | return -EINVAL; | 838 | return -EINVAL; |
814 | battery = acpi_driver_data(device); | 839 | battery = acpi_driver_data(device); |
815 | battery->update_time = 0; | 840 | battery->update_time = 0; |
841 | acpi_battery_update(battery); | ||
816 | return 0; | 842 | return 0; |
817 | } | 843 | } |
818 | 844 | ||