All pastes #409125 Raw Edit

Anonymous

public text v1 · immutable
#409125 ·published 2007-03-25 13:49 UTC
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");