diff options
Diffstat (limited to 'drivers/acpi/battery.c')
-rw-r--r-- | drivers/acpi/battery.c | 203 |
1 files changed, 126 insertions, 77 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 681e26b56b1..c4a769d1ba8 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -31,7 +31,7 @@ #include <linux/types.h> #include <linux/jiffies.h> -#ifdef CONFIG_ACPI_PROCFS +#ifdef CONFIG_ACPI_PROCFS_POWER #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <asm/uaccess.h> @@ -40,7 +40,9 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#ifdef CONFIG_ACPI_SYSFS_POWER #include <linux/power_supply.h> +#endif #define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF @@ -63,7 +65,7 @@ static unsigned int cache_time = 1000; module_param(cache_time, uint, 0644); MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); -#ifdef CONFIG_ACPI_PROCFS +#ifdef CONFIG_ACPI_PROCFS_POWER extern struct proc_dir_entry *acpi_lock_battery_dir(void); extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); @@ -86,7 +88,9 @@ MODULE_DEVICE_TABLE(acpi, battery_device_ids); struct acpi_battery { struct mutex lock; +#ifdef CONFIG_ACPI_SYSFS_POWER struct power_supply bat; +#endif struct acpi_device *device; unsigned long update_time; int current_now; @@ -117,6 +121,7 @@ inline int acpi_battery_present(struct acpi_battery *battery) return battery->device->status.battery_present; } +#ifdef CONFIG_ACPI_SYSFS_POWER static int acpi_battery_technology(struct acpi_battery *battery) { if (!strcasecmp("NiCd", battery->type)) @@ -125,19 +130,25 @@ static int acpi_battery_technology(struct acpi_battery *battery) return POWER_SUPPLY_TECHNOLOGY_NiMH; if (!strcasecmp("LION", battery->type)) return POWER_SUPPLY_TECHNOLOGY_LION; + if (!strncasecmp("LI-ION", battery->type, 6)) + return POWER_SUPPLY_TECHNOLOGY_LION; if (!strcasecmp("LiP", battery->type)) return POWER_SUPPLY_TECHNOLOGY_LIPO; return POWER_SUPPLY_TECHNOLOGY_UNKNOWN; } +static int acpi_battery_get_state(struct acpi_battery *battery); + static int acpi_battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { struct acpi_battery *battery = to_acpi_battery(psy); - if ((!acpi_battery_present(battery)) && - psp != POWER_SUPPLY_PROP_PRESENT) + if (acpi_battery_present(battery)) { + /* run battery update only if it is present */ + acpi_battery_get_state(battery); + } else if (psp != POWER_SUPPLY_PROP_PRESENT) return -ENODEV; switch (psp) { case POWER_SUPPLY_PROP_STATUS: @@ -147,6 +158,8 @@ static int acpi_battery_get_property(struct power_supply *psy, val->intval = POWER_SUPPLY_STATUS_CHARGING; else if (battery->state == 0) val->intval = POWER_SUPPLY_STATUS_FULL; + else + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; break; case POWER_SUPPLY_PROP_PRESENT: val->intval = acpi_battery_present(battery); @@ -214,8 +227,9 @@ static enum power_supply_property energy_battery_props[] = { POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_MANUFACTURER, }; +#endif -#ifdef CONFIG_ACPI_PROCFS +#ifdef CONFIG_ACPI_PROCFS_POWER inline char *acpi_battery_units(struct acpi_battery *battery) { return (battery->power_unit)?"mA":"mW"; @@ -257,7 +271,7 @@ static int extract_package(struct acpi_battery *battery, union acpi_object *package, struct acpi_offsets *offsets, int num) { - int i, *x; + int i; union acpi_object *element; if (package->type != ACPI_TYPE_PACKAGE) return -EFAULT; @@ -266,16 +280,21 @@ static int extract_package(struct acpi_battery *battery, return -EFAULT; element = &package->package.elements[i]; if (offsets[i].mode) { - if (element->type != ACPI_TYPE_STRING && - element->type != ACPI_TYPE_BUFFER) - return -EFAULT; - strncpy((u8 *)battery + offsets[i].offset, - element->string.pointer, 32); + u8 *ptr = (u8 *)battery + offsets[i].offset; + if (element->type == ACPI_TYPE_STRING || + element->type == ACPI_TYPE_BUFFER) + strncpy(ptr, element->string.pointer, 32); + else if (element->type == ACPI_TYPE_INTEGER) { + strncpy(ptr, (u8 *)&element->integer.value, + sizeof(acpi_integer)); + ptr[sizeof(acpi_integer)] = 0; + } else return -EFAULT; } else { - if (element->type != ACPI_TYPE_INTEGER) - return -EFAULT; - x = (int *)((u8 *)battery + offsets[i].offset); - *x = element->integer.value; + if (element->type == ACPI_TYPE_INTEGER) { + int *x = (int *)((u8 *)battery + + offsets[i].offset); + *x = element->integer.value; + } else return -EFAULT; } } return 0; @@ -385,29 +404,91 @@ static int acpi_battery_init_alarm(struct acpi_battery *battery) return acpi_battery_set_alarm(battery); } +#ifdef CONFIG_ACPI_SYSFS_POWER +static ssize_t acpi_battery_alarm_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); + return sprintf(buf, "%d\n", battery->alarm * 1000); +} + +static ssize_t acpi_battery_alarm_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long x; + struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); + if (sscanf(buf, "%ld\n", &x) == 1) + battery->alarm = x/1000; + if (acpi_battery_present(battery)) + acpi_battery_set_alarm(battery); + return count; +} + +static struct device_attribute alarm_attr = { + .attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE}, + .show = acpi_battery_alarm_show, + .store = acpi_battery_alarm_store, +}; + +static int sysfs_add_battery(struct acpi_battery *battery) +{ + int result; + + if (battery->power_unit) { + battery->bat.properties = charge_battery_props; + battery->bat.num_properties = + ARRAY_SIZE(charge_battery_props); + } else { + battery->bat.properties = energy_battery_props; + battery->bat.num_properties = + ARRAY_SIZE(energy_battery_props); + } + + battery->bat.name = acpi_device_bid(battery->device); + battery->bat.type = POWER_SUPPLY_TYPE_BATTERY; + battery->bat.get_property = acpi_battery_get_property; + + result = power_supply_register(&battery->device->dev, &battery->bat); + if (result) + return result; + return device_create_file(battery->bat.dev, &alarm_attr); +} + +static void sysfs_remove_battery(struct acpi_battery *battery) +{ + if (!battery->bat.dev) + return; + device_remove_file(battery->bat.dev, &alarm_attr); + power_supply_unregister(&battery->bat); + battery->bat.dev = NULL; +} +#endif + static int acpi_battery_update(struct acpi_battery *battery) { - int saved_present = acpi_battery_present(battery); - int result = acpi_battery_get_status(battery); - if (result || !acpi_battery_present(battery)) + int result; + result = acpi_battery_get_status(battery); + if (result) return result; - if (saved_present != acpi_battery_present(battery) || - !battery->update_time) { +#ifdef CONFIG_ACPI_SYSFS_POWER + if (!acpi_battery_present(battery)) { + sysfs_remove_battery(battery); battery->update_time = 0; + return 0; + } +#endif + if (!battery->update_time) { result = acpi_battery_get_info(battery); if (result) return result; - if (battery->power_unit) { - battery->bat.properties = charge_battery_props; - battery->bat.num_properties = - ARRAY_SIZE(charge_battery_props); - } else { - battery->bat.properties = energy_battery_props; - battery->bat.num_properties = - ARRAY_SIZE(energy_battery_props); - } acpi_battery_init_alarm(battery); } +#ifdef CONFIG_ACPI_SYSFS_POWER + if (!battery->bat.dev) + sysfs_add_battery(battery); +#endif return acpi_battery_get_state(battery); } @@ -415,7 +496,7 @@ static int acpi_battery_update(struct acpi_battery *battery) FS Interface (/proc) -------------------------------------------------------------------------- */ -#ifdef CONFIG_ACPI_PROCFS +#ifdef CONFIG_ACPI_PROCFS_POWER static struct proc_dir_entry *acpi_battery_dir; static int acpi_battery_print_info(struct seq_file *seq, int result) @@ -554,10 +635,6 @@ static ssize_t acpi_battery_write_alarm(struct file *file, if (!battery || (count > sizeof(alarm_string) - 1)) return -EINVAL; - if (result) { - result = -ENODEV; - goto end; - } if (!acpi_battery_present(battery)) { result = -ENODEV; goto end; @@ -688,33 +765,6 @@ static void acpi_battery_remove_fs(struct acpi_device *device) #endif -static ssize_t acpi_battery_alarm_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); - return sprintf(buf, "%d\n", battery->alarm * 1000); -} - -static ssize_t acpi_battery_alarm_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned long x; - struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); - if (sscanf(buf, "%ld\n", &x) == 1) - battery->alarm = x/1000; - if (acpi_battery_present(battery)) - acpi_battery_set_alarm(battery); - return count; -} - -static struct device_attribute alarm_attr = { - .attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE}, - .show = acpi_battery_alarm_show, - .store = acpi_battery_alarm_store, -}; - /* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */ @@ -732,7 +782,11 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) acpi_bus_generate_netlink_event(device->pnp.device_class, device->dev.bus_id, event, acpi_battery_present(battery)); - kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE); +#ifdef CONFIG_ACPI_SYSFS_POWER + /* acpi_batter_update could remove power_supply object */ + if (battery->bat.dev) + kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE); +#endif } static int acpi_battery_add(struct acpi_device *device) @@ -751,16 +805,11 @@ static int acpi_battery_add(struct acpi_device *device) acpi_driver_data(device) = battery; mutex_init(&battery->lock); acpi_battery_update(battery); -#ifdef CONFIG_ACPI_PROCFS +#ifdef CONFIG_ACPI_PROCFS_POWER result = acpi_battery_add_fs(device); if (result) goto end; #endif - battery->bat.name = acpi_device_bid(device); - battery->bat.type = POWER_SUPPLY_TYPE_BATTERY; - battery->bat.get_property = acpi_battery_get_property; - result = power_supply_register(&battery->device->dev, &battery->bat); - result = device_create_file(battery->bat.dev, &alarm_attr); status = acpi_install_notify_handler(device->handle, ACPI_ALL_NOTIFY, acpi_battery_notify, battery); @@ -774,7 +823,7 @@ static int acpi_battery_add(struct acpi_device *device) device->status.battery_present ? "present" : "absent"); end: if (result) { -#ifdef CONFIG_ACPI_PROCFS +#ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_remove_fs(device); #endif kfree(battery); @@ -793,13 +842,12 @@ static int acpi_battery_remove(struct acpi_device *device, int type) status = acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY, acpi_battery_notify); -#ifdef CONFIG_ACPI_PROCFS +#ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_remove_fs(device); #endif - if (battery->bat.dev) { - device_remove_file(battery->bat.dev, &alarm_attr); - power_supply_unregister(&battery->bat); - } +#ifdef CONFIG_ACPI_SYSFS_POWER + sysfs_remove_battery(battery); +#endif mutex_destroy(&battery->lock); kfree(battery); return 0; @@ -813,6 +861,7 @@ static int acpi_battery_resume(struct acpi_device *device) return -EINVAL; battery = acpi_driver_data(device); battery->update_time = 0; + acpi_battery_update(battery); return 0; } @@ -831,13 +880,13 @@ static int __init acpi_battery_init(void) { if (acpi_disabled) return -ENODEV; -#ifdef CONFIG_ACPI_PROCFS +#ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_dir = acpi_lock_battery_dir(); if (!acpi_battery_dir) return -ENODEV; #endif if (acpi_bus_register_driver(&acpi_battery_driver) < 0) { -#ifdef CONFIG_ACPI_PROCFS +#ifdef CONFIG_ACPI_PROCFS_POWER acpi_unlock_battery_dir(acpi_battery_dir); #endif return -ENODEV; @@ -848,7 +897,7 @@ static int __init acpi_battery_init(void) static void __exit acpi_battery_exit(void) { acpi_bus_unregister_driver(&acpi_battery_driver); -#ifdef CONFIG_ACPI_PROCFS +#ifdef CONFIG_ACPI_PROCFS_POWER acpi_unlock_battery_dir(acpi_battery_dir); #endif } |