rendered paste body/*
* battery.c
*
* Universal battery monitor class
*
* (c) 2003 Ian Molton <spyro@f2s.com>
*
* Modified: 2004, Oct Szabolcs Gyurko
*
* You may use this code as per GPL version 2
*
* Note: the battery class is NOT the place to put code to detect
* ac line status- this should be in a seperate 'power' class. -Spyro
*
* All volatges, currents, charges, and temperatures in mV, mA, mJ and
* tenths of a degree unless otherwise stated.
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/battery.h>
#define to_battery(obj) container_of(obj, struct battery, class_dev)
static ssize_t battery_show_id(struct class_device *cdev, char *buf) {
struct battery *bat = to_battery(cdev);
return sprintf(buf, "%s\n", bat->id);
}
static char *status_text[] = {"Unknown", "Charging", "Discharging", "Not charging"};
static ssize_t battery_show_status(struct class_device *cdev, char *buf) {
struct battery *bat = to_battery(cdev);
int status = 0;
if (bat->get_status) {
status = bat->get_status(bat);
if(status > 3) status = 0;
return sprintf(buf, "%s\n", status_text[status]);
}
return 0;
}
#define show_int_val(name) \
static ssize_t battery_show_##name(struct class_device *cdev, char *buf) { \
struct battery *bat = to_battery(cdev); \
if (bat->get_##name) \
return sprintf(buf, "%d\n", bat->get_##name(bat)); \
return 0; \
}
show_int_val(min_voltage); // in mV
show_int_val(min_current); // in mA
show_int_val(min_charge); // in mJ
show_int_val(max_voltage);
show_int_val(max_current);
show_int_val(max_charge);
show_int_val(temp); // in tenths of a deg *C* (we dont do fahrenheight)
show_int_val(voltage);
show_int_val(current);
show_int_val(charge);
/*
* This is because the name "current" breaks the device attr macro.
* The "current" word resolvs to "(get_current())" so instead of "current" "(get_current())"
* appears in the sysfs.
*
* The source of this definition is the device.h which calls __ATTR macro in sysfs.h
* which calls the __stringify macro.
*
* Only modification that the name is not tried to be resolved (as a macro let's say)
*/
#define BATTERY_CLS_DEV_ATTR(_name, _mode, _show, _store) \
struct class_device_attribute class_device_attr_##_name = { \
.attr = { .name = #_name, .mode = _mode, .owner = THIS_MODULE }, \
.show = _show, \
.store = _store, \
}
static BATTERY_CLS_DEV_ATTR (id, 0444, battery_show_id, NULL);
static BATTERY_CLS_DEV_ATTR (status, 0444, battery_show_status, NULL);
static BATTERY_CLS_DEV_ATTR (min_voltage, 0444, battery_show_min_voltage, NULL);
static BATTERY_CLS_DEV_ATTR (min_current, 0444, battery_show_min_current, NULL);
static BATTERY_CLS_DEV_ATTR (min_charge, 0444, battery_show_min_charge, NULL);
static BATTERY_CLS_DEV_ATTR (max_voltage, 0444, battery_show_max_voltage, NULL);
static BATTERY_CLS_DEV_ATTR (max_current, 0444, battery_show_max_current, NULL);
static BATTERY_CLS_DEV_ATTR (max_charge, 0444, battery_show_max_charge, NULL);
static BATTERY_CLS_DEV_ATTR (temp, 0444, battery_show_temp, NULL);
static BATTERY_CLS_DEV_ATTR (voltage, 0444, battery_show_voltage, NULL);
static BATTERY_CLS_DEV_ATTR (current, 0444, battery_show_current, NULL);
static BATTERY_CLS_DEV_ATTR (charge, 0444, battery_show_charge, NULL);
/*--------------------------------------------------------------*/
/* hotplug stuff */
#if 0
static int battery_class_hotplug(struct class_device *dev, char **envp,
int num_envp, char *buffer, int buffer_size)
{
struct battery *bat = to_battery(dev);
return 0;
}
#endif
static struct class battery_class = {
.name = "battery",
// .hotplug = battery_class_hotplug,
// .release = battery_class_release,
};
/*--------------------------------------------------------------*/
/* Register new batteries */
#define create_entry_conditional(name) \
if(bat->get_##name) { \
rc = class_device_create_file(&bat->class_dev, &class_device_attr_##name); \
if (rc) goto out; \
}
int battery_class_register(struct battery *bat)
{
int rc = 0;
WARN_ON(!bat->name);
bat->class_dev.class = &battery_class;
strcpy(bat->class_dev.class_id, bat->name);
rc = class_device_register(&bat->class_dev);
if(rc)
goto out;
if(bat->id) {
rc = class_device_create_file(&bat->class_dev, &class_device_attr_id);
if (rc) goto out;
}
create_entry_conditional(status);
create_entry_conditional(min_voltage);
create_entry_conditional(min_current);
create_entry_conditional(min_charge);
create_entry_conditional(max_voltage);
create_entry_conditional(max_current);
create_entry_conditional(max_charge);
create_entry_conditional(temp);
create_entry_conditional(voltage);
create_entry_conditional(current);
create_entry_conditional(charge);
out:
return rc;
}
EXPORT_SYMBOL (battery_class_register);
void battery_class_unregister (struct battery *bat)
{
class_device_unregister(&bat->class_dev);
}
EXPORT_SYMBOL (battery_class_unregister);
/*--------------------------------------------------------------*/
/* Init */
static int __init battery_class_init(void)
{
return class_register(&battery_class);
}
static void __exit battery_class_exit(void)
{
class_unregister(&battery_class);
}
#ifdef MODULE
module_init(battery_class_init);
#else /* start early */
subsys_initcall(battery_class_init);
#endif
module_exit(battery_class_exit);
MODULE_DESCRIPTION("Battery driver");
MODULE_AUTHOR("Ian Molton");
MODULE_LICENSE("GPL");