ACPI: Battery: add sysfs support
PATCH 1/1 ACPI: Battery: add sysfs support
Hi Len,
This is a first try to add sysfs support for ACPI battery.
It should apply on top of clean up patches I sent earlier.
It lacks alarm support in sysfs, as power_supply class does not support it.
Regards,
Alex.
ACPI: Battery: Add sysfs support
From: Alexey Starikovskiy <[email protected]>
---
drivers/acpi/battery.c | 201 +++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 179 insertions(+), 22 deletions(-)
drivers/acpi/battery.c +179 -22
@@ -30,13 +30,21 @@#include <linux/init.h> #include <linux/types.h> #include <linux/jiffies.h> + +#ifdef CONFIG_ACPI_PROC #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <asm/uaccess.h> +#endif #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#if defined(CONFIG_POWER_SUPPLY ) || defined(CONFIG_POWER_SUPPLY_MODULE ) +#define ENABLE_POWER_SUPPLY +#include <linux/power_supply.h> +#endif +#define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF#define ACPI_BATTERY_COMPONENT 0x00040000
@@ -58,9 +66,19 @@ static unsigned int cache_time = 1000;module_param (cache_time, uint,0644 );MODULE_PARM_DESC (cache_time,"cache time in milliseconds" ); +#ifdef CONFIG_ACPI_PROC extern struct proc_dir_entry *acpi_lock_battery_dir (void );extern void *acpi_unlock_battery_dir (struct proc_dir_entry *acpi_battery_dir); +enum acpi_battery_files { + info_tag =0 , + state_tag, + alarm_tag, +ACPI_BATTERY_NUMFILES , +}; + +#endif +static const struct acpi_device_id battery_device_ids[] = { {"PNP0C0A" ,0 }, {"" ,0 },
@@ -68,22 +86,19 @@ static const struct acpi_device_id battery_device_ids[] = {MODULE_DEVICE_TABLE (acpi, battery_device_ids); -enum acpi_battery_files { - info_tag =0 , - state_tag, - alarm_tag, -ACPI_BATTERY_NUMFILES , -};struct acpi_battery {struct mutex lock; +#ifdef ENABLE_POWER_SUPPLY +struct power_supply bat; +#endif struct acpi_device *device;unsigned long update_time; -int present_rate; -int remaining_capacity; -int present_voltage; +int current_now; +int capacity_now; +int voltage_now;int design_capacity; -int last_full_capacity; +int full_charge_capacity;int technology;int design_voltage;int design_capacity_warning;
@@ -100,15 +115,119 @@ struct acpi_battery {u8 alarm_present; }; +#define to_acpi_battery (x) container_of(x, struct acpi_battery, bat); +inline int acpi_battery_present (struct acpi_battery *battery) {return battery->device->status.battery_present; } +#ifdef ENABLE_POWER_SUPPLY +static int acpi_battery_technology (struct acpi_battery *battery) +{ +if (!strcasecmp ("NiCd" , battery->type)) +return POWER_SUPPLY_TECHNOLOGY_NiCd; +if (!strcasecmp ("NiMH" , battery->type)) +return POWER_SUPPLY_TECHNOLOGY_NiMH; +if (!strcasecmp ("LION" , battery->type)) +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_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 ) +return -ENODEV ; +switch (psp) { +case POWER_SUPPLY_PROP_STATUS : +if (battery->state &0x01 ) + val->intval =POWER_SUPPLY_STATUS_DISCHARGING ; +else if (battery->state &0x02 ) + val->intval =POWER_SUPPLY_STATUS_CHARGING ; +else if (battery->state ==0 ) + val->intval =POWER_SUPPLY_STATUS_FULL ; +break ; +case POWER_SUPPLY_PROP_PRESENT : + val->intval =acpi_battery_present (battery); +break ; +case POWER_SUPPLY_PROP_TECHNOLOGY : + val->intval =acpi_battery_technology (battery); +break ; +case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN : + val->intval = battery->design_voltage *1000 ; +break ; +case POWER_SUPPLY_PROP_VOLTAGE_NOW : + val->intval = battery->voltage_now *1000 ; +break ; +case POWER_SUPPLY_PROP_CURRENT_NOW : + val->intval = battery->current_now *1000 ; +break ; +case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN : +case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN : + val->intval = battery->design_capacity *1000 ; +break ; +case POWER_SUPPLY_PROP_CHARGE_FULL : +case POWER_SUPPLY_PROP_ENERGY_FULL : + val->intval = battery->full_charge_capacity *1000 ; +break ; +case POWER_SUPPLY_PROP_CHARGE_NOW : +case POWER_SUPPLY_PROP_ENERGY_NOW : + val->intval = battery->capacity_now *1000 ; +break ; +case POWER_SUPPLY_PROP_MODEL_NAME : + val->strval = battery->model_number; +break ; +case POWER_SUPPLY_PROP_MANUFACTURER : + val->strval = battery->oem_info; +break ; +default : +return -EINVAL ; + } +return 0 ; +} + +static enum power_supply_property charge_battery_props[] = { +POWER_SUPPLY_PROP_STATUS , +POWER_SUPPLY_PROP_PRESENT , +POWER_SUPPLY_PROP_TECHNOLOGY , +POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN , +POWER_SUPPLY_PROP_VOLTAGE_NOW , +POWER_SUPPLY_PROP_CURRENT_NOW , +POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN , +POWER_SUPPLY_PROP_CHARGE_FULL , +POWER_SUPPLY_PROP_CHARGE_NOW , +POWER_SUPPLY_PROP_MODEL_NAME , +POWER_SUPPLY_PROP_MANUFACTURER , +}; + +static enum power_supply_property energy_battery_props[] = { +POWER_SUPPLY_PROP_STATUS , +POWER_SUPPLY_PROP_PRESENT , +POWER_SUPPLY_PROP_TECHNOLOGY , +POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN , +POWER_SUPPLY_PROP_VOLTAGE_NOW , +POWER_SUPPLY_PROP_CURRENT_NOW , +POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN , +POWER_SUPPLY_PROP_ENERGY_FULL , +POWER_SUPPLY_PROP_ENERGY_NOW , +POWER_SUPPLY_PROP_MODEL_NAME , +POWER_SUPPLY_PROP_MANUFACTURER , +}; +#endif + +#ifdef CONFIG_ACPI_PROC inline char *acpi_battery_units (struct acpi_battery *battery) {return (battery->power_unit)?"mA" :"mW" ; } +#endif /* -------------------------------------------------------------------------- Battery Management
@@ -120,15 +239,15 @@ struct acpi_offsets {static struct acpi_offsets state_offsets[] = { {offsetof(struct acpi_battery , state),0 }, - {offsetof(struct acpi_battery , present_rate),0 }, - {offsetof(struct acpi_battery , remaining_capacity),0 }, - {offsetof(struct acpi_battery , present_voltage),0 }, + {offsetof(struct acpi_battery , current_now),0 }, + {offsetof(struct acpi_battery , capacity_now),0 }, + {offsetof(struct acpi_battery , voltage_now),0 }, };static struct acpi_offsets info_offsets[] = { {offsetof(struct acpi_battery , power_unit),0 }, {offsetof(struct acpi_battery , design_capacity),0 }, - {offsetof(struct acpi_battery , last_full_capacity),0 }, + {offsetof(struct acpi_battery , full_charge_capacity),0 }, {offsetof(struct acpi_battery , technology),0 }, {offsetof(struct acpi_battery , design_voltage),0 }, {offsetof(struct acpi_battery , design_capacity_warning),0 },
@@ -286,6 +405,17 @@ static int acpi_battery_update(struct acpi_battery *battery) result =acpi_battery_get_info (battery);if (result)return result; +#ifdef ENABLE_POWER_SUPPLY +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); + } +#endif acpi_battery_init_alarm (battery); }return acpi_battery_get_state (battery);
@@ -295,6 +425,7 @@ static int acpi_battery_update(struct acpi_battery *battery)FS Interface (/proc) -------------------------------------------------------------------------- */ +#ifdef CONFIG_ACPI_PROC static struct proc_dir_entry *acpi_battery_dir;static int acpi_battery_print_info (struct seq_file *seq,int result)
@@ -315,11 +446,11 @@ static int acpi_battery_print_info(struct seq_file *seq, int result) battery->design_capacity, acpi_battery_units(battery)); -if (battery->last_full_capacity ==ACPI_BATTERY_VALUE_UNKNOWN ) +if (battery->full_charge_capacity ==ACPI_BATTERY_VALUE_UNKNOWN )seq_printf (seq,"last full capacity: unknown\n" );else seq_printf (seq,"last full capacity: %d %sh\n" , - battery->last_full_capacity, + battery->full_charge_capacity,acpi_battery_units (battery)); seq_printf(seq, "battery technology: %srechargeable\n",
@@ -376,22 +507,22 @@ static int acpi_battery_print_state(struct seq_file *seq, int result)else seq_printf (seq,"charging state: charged\n" ); -if (battery->present_rate ==ACPI_BATTERY_VALUE_UNKNOWN ) +if (battery->current_now ==ACPI_BATTERY_VALUE_UNKNOWN )seq_printf (seq,"present rate: unknown\n" );else seq_printf (seq,"present rate: %d %s\n" , - battery->present_rate,acpi_battery_units (battery)); + battery->current_now,acpi_battery_units (battery)); -if (battery->remaining_capacity ==ACPI_BATTERY_VALUE_UNKNOWN ) +if (battery->capacity_now ==ACPI_BATTERY_VALUE_UNKNOWN )seq_printf (seq,"remaining capacity: unknown\n" );else seq_printf (seq,"remaining capacity: %d %sh\n" , - battery->remaining_capacity,acpi_battery_units (battery)); -if (battery->present_voltage ==ACPI_BATTERY_VALUE_UNKNOWN ) + battery->capacity_now,acpi_battery_units (battery)); +if (battery->voltage_now ==ACPI_BATTERY_VALUE_UNKNOWN )seq_printf (seq,"present voltage: unknown\n" );else seq_printf (seq,"present voltage: %d mV\n" , - battery->present_voltage); + battery->voltage_now); end:if (result)seq_printf (seq,"ERROR: Unable to read battery state\n" );
@@ -565,6 +696,7 @@ static void acpi_battery_remove_fs(struct acpi_device *device) acpi_device_dir(device) = NULL; } +#endif /* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */
@@ -577,6 +709,9 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)acpi_battery_update (battery);acpi_bus_generate_event (battery->device, event,acpi_battery_present (battery)); +#ifdef ENABLE_POWER_SUPPLY +kobject_uevent (&battery->bat.dev->kobj,KOBJ_CHANGE ); +#endif }static int acpi_battery_add (struct acpi_device *device)
@@ -595,9 +730,17 @@ static int acpi_battery_add(struct acpi_device *device)strcpy (acpi_device_class (device),ACPI_BATTERY_CLASS );acpi_driver_data (device) = battery;acpi_battery_update (battery); +#ifdef CONFIG_ACPI_PROC result =acpi_battery_add_fs (device);if (result) goto end; +#endif +#ifdef ENABLE_POWER_SUPPLY + 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); +#endif status =acpi_install_notify_handler (device->handle,ACPI_ALL_NOTIFY , acpi_battery_notify, battery);
@@ -611,7 +754,9 @@ static int acpi_battery_add(struct acpi_device *device) device->status.battery_present ? "present" : "absent"); end:if (result) { +#ifdef CONFIG_ACPI_PROC acpi_battery_remove_fs (device); +#endif kfree (battery); }return result;
@@ -628,7 +773,13 @@ 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_PROC acpi_battery_remove_fs (device); +#endif +#ifdef ENABLE_POWER_SUPPLY +if (battery->bat.dev) +power_supply_unregister (&battery->bat); +#endif mutex_destroy (&battery->lock);kfree (battery);return 0 ;
@@ -660,11 +811,15 @@ static int __init acpi_battery_init(void) {if (acpi_disabled)return -ENODEV ; +#ifdef CONFIG_ACPI_PROC 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_PROC acpi_unlock_battery_dir (acpi_battery_dir); +#endif return -ENODEV ; }return 0 ;
@@ -673,7 +828,9 @@ static int __init acpi_battery_init(void) static void __exit acpi_battery_exit(void) {acpi_bus_unregister_driver (&acpi_battery_driver); +#ifdef CONFIG_ACPI_PROC acpi_unlock_battery_dir (acpi_battery_dir); +#endif }module_init (acpi_battery_init);
Len Brown
reviewerQuoted 5 lines · Alexey Starikovskiy
Hi Len,
This is a first try to add sysfs support for ACPI battery.
It should apply on top of clean up patches I sent earlier.
It lacks alarm support in sysfs, aspower_supplyclass does not support it.
The check-in comments should describe the sysfs support. it is an API that is being created here -- after all.
thanks,
-len
Quoted 7 lines · Len Brown
Quoted 5 lines · Alexey Starikovskiy
Hi Len,
This is a first try to add sysfs support for ACPI battery.
It should apply on top of clean up patches I sent earlier.
It lacks alarm support in sysfs, aspower_supplyclass does not support it.
Quoted 6 lines
The check-in comments should describe the sysfs support. it is an API that is being created here -- after all.
thanks,
-len
No, we are using standard class power_supply and its API. So all the documentation is already present in kernel.
Regards,
Alex