Battery class driver.

Dan Williams dcbw at redhat.com
Mon Oct 23 15:18:11 EDT 2006


Adding Richard Hughes and David Zeuthen, since they will actually have
to talk to your batter class and driver.

On Mon, 2006-10-23 at 19:32 +0100, David Woodhouse wrote:
> At git://git.infradead.org/battery-2.6.git there is an initial
> implementation of a battery class, along with a driver which makes use
> of it. The patch is below, and also viewable at 
> http://git.infradead.org/?p=battery-2.6.git;a=commitdiff;h=master;hp=linus
> 
> I don't like the sysfs interaction much -- is it really necessary for me
> to provide a separate function for each attribute, rather than a single
> function which handles them all and is given the individual attribute as
> an argument? That seems strange and bloated.
> 
> I'm half tempted to ditch the sysfs attributes and just use a single
> seq_file, in fact.
> 
> The idea is that all batteries should be presented to userspace through
> this class instead of through the existing mess of PMU/APM/ACPI and even
> APM _emulation_.
> 
> I think I probably want to make AC power a separate 'device' too, rather
> than an attribute of any given battery. And when there are multiple
> power supplies, there should be multiple such devices. So maybe it
> should be a 'power supply' class, not a battery class at all?
> 
> Comments? 
> 
> 
> commit 42fe507a262b2a2879ca62740c5312778ae78627
> Author: David Woodhouse <dwmw2 at infradead.org>
> Date:   Mon Oct 23 18:14:54 2006 +0100
> 
>     [BATTERY] Add support for OLPC battery
>     
>     Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
> 
> commit 6cbec3b84e3ce737b4217788841ea10a28a5e340
> Author: David Woodhouse <dwmw2 at infradead.org>
> Date:   Mon Oct 23 18:14:14 2006 +0100
> 
>     [BATTERY] Add initial implementation of battery class
>     
>     I really don't like the sysfs interaction, and I don't much like the
>     internal interaction with the battery drivers either. In fact, there
>     isn't much I _do_ like, but it's good enough as a straw man.
>     
>     Signed-off-by: David Woodhouse <dwmw2 at infradead.org>
> 
> --- drivers/Makefile~	2006-10-19 19:51:32.000000000 +0100
> +++ drivers/Makefile	2006-10-23 15:27:47.000000000 +0100
> @@ -30,6 +30,7 @@ obj-$(CONFIG_PARPORT)		+= parport/
>  obj-y				+= base/ block/ misc/ mfd/ net/ media/
>  obj-$(CONFIG_NUBUS)		+= nubus/
>  obj-$(CONFIG_ATM)		+= atm/
> +obj-$(CONFIG_BATTERY_CLASS)	+= battery/
>  obj-$(CONFIG_PPC_PMAC)		+= macintosh/
>  obj-$(CONFIG_XEN)		+= xen/
>  obj-$(CONFIG_IDE)		+= ide/
> --- drivers/Kconfig~	2006-09-20 04:42:06.000000000 +0100
> +++ drivers/Kconfig	2006-10-23 15:27:42.000000000 +0100
> @@ -28,6 +28,8 @@ source "drivers/ieee1394/Kconfig"
>  
>  source "drivers/message/i2o/Kconfig"
>  
> +source "drivers/battery/Kconfig"
> +
>  source "drivers/macintosh/Kconfig"
>  
>  source "drivers/net/Kconfig"
> --- /dev/null	2006-10-01 17:20:05.827666723 +0100
> +++ drivers/battery/Makefile	2006-10-23 16:53:20.000000000 +0100
> @@ -0,0 +1,4 @@
> +# Battery code
> +obj-$(CONFIG_BATTERY_CLASS)		+= battery-class.o
> +
> +obj-$(CONFIG_OLPC_BATTERY)		+= olpc-battery.o
> --- /dev/null	2006-10-01 17:20:05.827666723 +0100
> +++ drivers/battery/Kconfig	2006-10-23 16:52:42.000000000 +0100
> @@ -0,0 +1,22 @@
> +
> +menu "Battery support"
> +
> +config BATTERY_CLASS
> +       tristate "Battery support"
> +       help
> +         Say Y to enable battery class support. This allows a battery
> +	 information to be presented in a uniform manner for all types
> +	 of batteries.
> +
> +	 Battery information from APM and ACPI is not yet available by
> +	 this method, but should soon be. If you use APM or ACPI, say
> +	 'N', although saying 'Y' would be harmless.
> +
> +config OLPC_BATTERY
> +       tristate "One Laptop Per Child battery"
> +       depends on BATTERY_CLASS && X86_32
> +       help
> +         Say Y to enable support for the battery on the $100 laptop.
> +
> +
> +endmenu
> --- /dev/null	2006-10-01 17:20:05.827666723 +0100
> +++ drivers/battery/battery-class.c	2006-10-23 17:59:04.000000000 +0100
> @@ -0,0 +1,286 @@
> +/*
> + * Battery class core
> + *
> + *	© 2006 David Woodhouse <dwmw2 at infradead.org>
> + *
> + * Based on LED Class support, by John Lenz and Richard Purdie:
> + *
> + *	© 2005 John Lenz <lenz at cs.wisc.edu>
> + *	© 2005-2006 Richard Purdie <rpurdie at openedhand.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/device.h>
> +#include <linux/battery.h>
> +#include <linux/spinlock.h>
> +#include <linux/err.h>
> +
> +static struct class *battery_class;
> +
> +/* OMFG we can't just have a single 'show' routine which is given the
> +   'class_attribute' as an argument -- we have to have 20-odd copies
> +   of almost identical routines */
> +
> +static ssize_t battery_attribute_show_int(struct class_device *dev, char *buf, int attr)
> +{
> +        struct battery_classdev *battery_cdev = class_get_devdata(dev);
> +        ssize_t ret = 0;
> +	long value;
> +
> +	ret =  battery_cdev->query_long(battery_cdev, attr, &value);
> +	if (ret)
> +		return ret;
> +
> +	sprintf(buf, "%ld\n", value);
> +        ret = strlen(buf) + 1;
> +
> +        return ret;
> +}  
> +
> +static ssize_t battery_attribute_show_milli(struct class_device *dev, char *buf, int attr)
> +{
> +        struct battery_classdev *battery_cdev = class_get_devdata(dev);
> +        ssize_t ret = 0;
> +	long value;
> +
> +	ret = battery_cdev->query_long(battery_cdev, attr, &value);
> +	if (ret)
> +		return ret;
> +
> +	sprintf(buf, "%ld.%03ld\n", value/1000, value % 1000);
> +        ret = strlen(buf) + 1;
> +        return ret;
> +}  
> +
> +static ssize_t battery_attribute_show_string(struct class_device *dev, char *buf, int attr)
> +{
> +        struct battery_classdev *battery_cdev = class_get_devdata(dev);
> +        ssize_t ret = 0;
> +
> +	ret = battery_cdev->query_str(battery_cdev, attr, buf, PAGE_SIZE-1);
> +	if (ret)
> +		return ret;
> +
> +	strcat(buf, "\n");
> +        ret = strlen(buf) + 1;
> +        return ret;
> +}  
> +
> +static ssize_t battery_attribute_show_status(struct class_device *dev, char *buf)
> +{
> +        struct battery_classdev *battery_cdev = class_get_devdata(dev);
> +        ssize_t ret = 0;
> +	unsigned long status;
> +
> +	status = battery_cdev->status(battery_cdev, ~BAT_STAT_AC);
> +	if (status & BAT_STAT_ERROR)
> +		return -EIO;
> +
> +	if (status & BAT_STAT_PRESENT)
> +		sprintf(buf, "present");
> +	else
> +		sprintf(buf, "absent");
> +
> +	if (status & BAT_STAT_LOW)
> +		strcat(buf, ",low");
> +
> +	if (status & BAT_STAT_FULL)
> +		strcat(buf, ",full");
> +
> +	if (status & BAT_STAT_CHARGING)
> +		strcat(buf, ",charging");
> +
> +	if (status & BAT_STAT_DISCHARGING)
> +		strcat(buf, ",discharging");
> +
> +	if (status & BAT_STAT_OVERTEMP)
> +		strcat(buf, ",overtemp");
> +
> +	if (status & BAT_STAT_FIRE)
> +		strcat(buf, ",on-fire");
> +
> +	if (status & BAT_STAT_CHARGE_DONE)
> +		strcat(buf, ",charge-done");
> +
> +	strcat(buf, "\n");
> +        ret = strlen(buf) + 1;
> +        return ret;
> +}
> +
> +static ssize_t battery_attribute_show_ac_status(struct class_device *dev, char *buf)
> +{
> +        struct battery_classdev *battery_cdev = class_get_devdata(dev);
> +        ssize_t ret = 0;
> +	unsigned long status;
> +
> +	status = battery_cdev->status(battery_cdev, BAT_STAT_AC);
> +	if (status & BAT_STAT_ERROR)
> +		return -EIO;
> +
> +	if (status & BAT_STAT_AC)
> +		sprintf(buf, "on-line");
> +	else
> +		sprintf(buf, "off-line");
> +
> +	strcat(buf, "\n");
> +        ret = strlen(buf) + 1;
> +        return ret;
> +}  
> +
> +/* Ew. We can't even use CLASS_DEVICE_ATTR() if we want one named 'current' */
> +#define BATTERY_DEVICE_ATTR(_name, _attr, _type) \
> +static ssize_t battery_attr_show_##_attr(struct class_device *dev, char *buf)	\
> +{										\
> +	return battery_attribute_show_##_type(dev, buf, BAT_INFO_##_attr);	\
> +}										\
> +static struct class_device_attribute class_device_attr_##_attr  = {		\
> +        .attr = { .name = _name, .mode = 0444, .owner = THIS_MODULE },		\
> +	.show = battery_attr_show_##_attr };
> +
> +static CLASS_DEVICE_ATTR(status,0444,battery_attribute_show_status, NULL);
> +static CLASS_DEVICE_ATTR(ac,0444,battery_attribute_show_ac_status, NULL);
> +BATTERY_DEVICE_ATTR("temp1",TEMP1,milli);
> +BATTERY_DEVICE_ATTR("temp1_name",TEMP1_NAME,string);
> +BATTERY_DEVICE_ATTR("temp2",TEMP2,milli);
> +BATTERY_DEVICE_ATTR("temp2_name",TEMP2_NAME,string);
> +BATTERY_DEVICE_ATTR("voltage",VOLTAGE,milli);
> +BATTERY_DEVICE_ATTR("voltage_design",VOLTAGE_DESIGN,milli);
> +BATTERY_DEVICE_ATTR("current",CURRENT,milli);
> +BATTERY_DEVICE_ATTR("charge_rate",CHARGE_RATE,milli);
> +BATTERY_DEVICE_ATTR("charge_max",CHARGE_MAX,milli);
> +BATTERY_DEVICE_ATTR("charge_last",CHARGE_LAST,milli);
> +BATTERY_DEVICE_ATTR("charge_low",CHARGE_LOW,milli);
> +BATTERY_DEVICE_ATTR("charge_warn",CHARGE_WARN,milli);
> +BATTERY_DEVICE_ATTR("charge_unit",CHARGE_UNITS,string);
> +BATTERY_DEVICE_ATTR("charge_percent",CHARGE_PCT,int);
> +BATTERY_DEVICE_ATTR("time_remaining",TIME_REMAINING,int);
> +BATTERY_DEVICE_ATTR("manufacturer",MANUFACTURER,string);
> +BATTERY_DEVICE_ATTR("technology",TECHNOLOGY,string);
> +BATTERY_DEVICE_ATTR("model",MODEL,string);
> +BATTERY_DEVICE_ATTR("serial",SERIAL,string);
> +BATTERY_DEVICE_ATTR("type",TYPE,string);
> +BATTERY_DEVICE_ATTR("oem_info",OEM_INFO,string);
> +
> +#define REGISTER_ATTR(_attr)							\
> +	if (battery_cdev->capabilities & (1<<BAT_INFO_##_attr))			\
> +		class_device_create_file(battery_cdev->class_dev,		\
> +					 &class_device_attr_##_attr);
> +#define UNREGISTER_ATTR(_attr)							\
> +	if (battery_cdev->capabilities & (1<<BAT_INFO_##_attr))			\
> +		class_device_remove_file(battery_cdev->class_dev,		\
> +					 &class_device_attr_##_attr);
> +/**
> + * battery_classdev_register - register a new object of battery_classdev class.
> + * @dev: The device to register.
> + * @battery_cdev: the battery_classdev structure for this device.
> + */
> +int battery_classdev_register(struct device *parent, struct battery_classdev *battery_cdev)
> +{
> +        battery_cdev->class_dev = class_device_create(battery_class, NULL, 0,
> +						      parent, "%s", battery_cdev->name);
> +
> +        if (unlikely(IS_ERR(battery_cdev->class_dev)))
> +                return PTR_ERR(battery_cdev->class_dev);
> +
> +        class_set_devdata(battery_cdev->class_dev, battery_cdev);
> +
> +        /* register the attributes */
> +        class_device_create_file(battery_cdev->class_dev,
> +                                &class_device_attr_status);
> +
> +        if (battery_cdev->status_cap & (1<<BAT_STAT_AC))
> +		class_device_create_file(battery_cdev->class_dev, &class_device_attr_ac);
> +
> +	REGISTER_ATTR(TEMP1);
> +	REGISTER_ATTR(TEMP1_NAME);
> +	REGISTER_ATTR(TEMP2);
> +	REGISTER_ATTR(TEMP2_NAME);
> +	REGISTER_ATTR(VOLTAGE);
> +	REGISTER_ATTR(VOLTAGE_DESIGN);
> +	REGISTER_ATTR(CHARGE_PCT);
> +	REGISTER_ATTR(CURRENT);
> +	REGISTER_ATTR(CHARGE_RATE);
> +	REGISTER_ATTR(CHARGE_MAX);
> +	REGISTER_ATTR(CHARGE_LAST);
> +	REGISTER_ATTR(CHARGE_LOW);
> +	REGISTER_ATTR(CHARGE_WARN);
> +	REGISTER_ATTR(CHARGE_UNITS);
> +	REGISTER_ATTR(TIME_REMAINING);
> +	REGISTER_ATTR(MANUFACTURER);
> +	REGISTER_ATTR(TECHNOLOGY);
> +	REGISTER_ATTR(MODEL);
> +	REGISTER_ATTR(SERIAL);
> +	REGISTER_ATTR(TYPE);
> +	REGISTER_ATTR(OEM_INFO);
> +
> +        printk(KERN_INFO "Registered battery device: %s\n",
> +                        battery_cdev->class_dev->class_id);
> +
> +        return 0;
> +}
> +EXPORT_SYMBOL_GPL(battery_classdev_register);
> +
> +/**
> + * battery_classdev_unregister - unregisters a object of battery_properties class.
> + * @battery_cdev: the battery device to unreigister
> + *
> + * Unregisters a previously registered via battery_classdev_register object.
> + */
> +void battery_classdev_unregister(struct battery_classdev *battery_cdev)
> +{
> +        class_device_remove_file(battery_cdev->class_dev,
> +				 &class_device_attr_status);
> +
> +        if (battery_cdev->status_cap & (1<<BAT_STAT_AC))
> +		class_device_remove_file(battery_cdev->class_dev, &class_device_attr_ac);
> +
> +	UNREGISTER_ATTR(TEMP1);
> +	UNREGISTER_ATTR(TEMP1_NAME);
> +	UNREGISTER_ATTR(TEMP2);
> +	UNREGISTER_ATTR(TEMP2_NAME);
> +	UNREGISTER_ATTR(VOLTAGE);
> +	UNREGISTER_ATTR(VOLTAGE_DESIGN);
> +	UNREGISTER_ATTR(CHARGE_PCT);
> +	UNREGISTER_ATTR(CURRENT);
> +	UNREGISTER_ATTR(CHARGE_RATE);
> +	UNREGISTER_ATTR(CHARGE_MAX);
> +	UNREGISTER_ATTR(CHARGE_LAST);
> +	UNREGISTER_ATTR(CHARGE_LOW);
> +	UNREGISTER_ATTR(CHARGE_WARN);
> +	UNREGISTER_ATTR(CHARGE_UNITS);
> +	UNREGISTER_ATTR(TIME_REMAINING);
> +	UNREGISTER_ATTR(MANUFACTURER);
> +	UNREGISTER_ATTR(TECHNOLOGY);
> +	UNREGISTER_ATTR(MODEL);
> +	UNREGISTER_ATTR(SERIAL);
> +	UNREGISTER_ATTR(TYPE);
> +	UNREGISTER_ATTR(OEM_INFO);
> +
> +        class_device_unregister(battery_cdev->class_dev);
> +}
> +EXPORT_SYMBOL_GPL(battery_classdev_unregister);
> +
> +static int __init battery_init(void)
> +{
> +        battery_class = class_create(THIS_MODULE, "battery");
> +        if (IS_ERR(battery_class))
> +                return PTR_ERR(battery_class);
> +        return 0;
> +}
> +
> +static void __exit battery_exit(void)
> +{
> +        class_destroy(battery_class);
> +}
> +
> +subsys_initcall(battery_init);
> +module_exit(battery_exit);
> +
> +MODULE_AUTHOR("David Woodhouse <dwmw2 at infradead.org>");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Battery class interface");
> --- /dev/null	2006-10-01 17:20:05.827666723 +0100
> +++ drivers/battery/olpc-battery.c	2006-10-23 17:56:38.000000000 +0100
> @@ -0,0 +1,198 @@
> +/*
> + * Battery driver for One Laptop Per Child ($100 laptop) board.
> + *
> + *	© 2006 David Woodhouse <dwmw2 at infradead.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/device.h>
> +#include <linux/battery.h>
> +#include <linux/spinlock.h>
> +#include <linux/err.h>
> +#include <asm/io.h>
> +
> +#define wBAT_VOLTAGE		0xf900 /* *9.76/32,    mV */
> +#define wBAT_CURRENT		0xf902 /* *15.625/120, mA */
> +#define wBAT_TEMP		0xf906 /* *256/1000,   °C */
> +#define wAMB_TEMP		0xf908 /* *256/1000,   °C */
> +#define SOC			0xf910 /*      percentage */
> +#define sMBAT_STATUS		0xfaa4
> +#define		sBAT_PRESENT		1
> +#define		sBAT_FULL		2
> +#define		sBAT_DESTROY		4
> +#define		sBAT_LOW			32
> +#define		sBAT_DISCHG		64
> +#define sMCHARGE_STATUS		0xfaa5
> +#define		sBAT_CHARGE		1
> +#define		sBAT_OVERTEMP		4
> +#define		sBAT_NiMH		8
> +#define sPOWER_FLAG		0xfa40
> +#define		ADAPTER_IN		1
> +
> +static int lock_ec(void)
> +{
> +	unsigned long timeo = jiffies + HZ/20;
> +
> +	while (1) {
> +                unsigned char lock = inb(0x6c) & 0x80;
> +                if (!lock)
> +                        return 0;
> +		if (time_after(jiffies, timeo))
> +			return 1;
> +                yield();
> +        }
> +}
> +
> +static void unlock_ec(void)
> +{
> +        outb(0xff, 0x6c);
> +}
> +
> +unsigned char read_ec_byte(unsigned short adr)
> +{
> +        outb(adr >> 8, 0x381);
> +        outb(adr, 0x382);
> +        return inb(0x383);
> +}
> +
> +unsigned short read_ec_word(unsigned short adr)
> +{
> +        return (read_ec_byte(adr) << 8) | read_ec_byte(adr+1);
> +}
> +
> +unsigned long olpc_bat_status(struct battery_classdev *cdev, unsigned long mask)
> +{
> +	unsigned long result = 0;
> +	unsigned short tmp;
> +
> +	if (lock_ec()) {
> +		printk(KERN_ERR "Failed to lock EC for battery access\n");
> +		return BAT_STAT_ERROR;
> +	}
> +
> +	if (mask & BAT_STAT_AC) {
> +		if (read_ec_byte(sPOWER_FLAG) & ADAPTER_IN)
> +			result |= BAT_STAT_AC;
> +	}
> +	if (mask & (BAT_STAT_PRESENT|BAT_STAT_FULL|BAT_STAT_FIRE|BAT_STAT_LOW|BAT_STAT_DISCHARGING)) {
> +		tmp = read_ec_byte(sMBAT_STATUS);
> +		
> +		if (tmp & sBAT_PRESENT)
> +			result |= BAT_STAT_PRESENT;
> +		if (tmp & sBAT_FULL)
> +			result |= BAT_STAT_FULL;
> +		if (tmp & sBAT_DESTROY)
> +			result |= BAT_STAT_FIRE;
> +		if (tmp & sBAT_LOW)
> +			result |= BAT_STAT_LOW;
> +		if (tmp & sBAT_DISCHG)
> +			result |= BAT_STAT_DISCHARGING;
> +	}
> +	if (mask & (BAT_STAT_CHARGING|BAT_STAT_OVERTEMP)) {
> +		tmp = read_ec_byte(sMCHARGE_STATUS);
> +		if (tmp & sBAT_CHARGE)
> +			result |= BAT_STAT_CHARGING;
> +		if (tmp & sBAT_OVERTEMP)
> +			result |= BAT_STAT_OVERTEMP;
> +	}
> +	unlock_ec();
> +	return result;
> +}
> +
> +int olpc_bat_query_long(struct battery_classdev *dev, int attr, long *result)
> +{
> +	int ret = 0;
> +
> +	if (lock_ec())
> +		return -EIO;
> +
> +	if (!(read_ec_byte(sMBAT_STATUS) & sBAT_PRESENT)) {
> +		ret = -ENODEV;
> +	} else if (attr == BAT_INFO_VOLTAGE) {
> +		*result = read_ec_word(wBAT_VOLTAGE) * 9760 / 32000;
> +	} else if (attr == BAT_INFO_CURRENT) {
> +		*result = read_ec_word(wBAT_CURRENT) * 15625 / 120000;
> +	} else if (attr == BAT_INFO_TEMP1) {
> +		*result = read_ec_word(wBAT_TEMP) * 1000 / 256;
> +	} else if (attr == BAT_INFO_TEMP2) {
> +		*result = read_ec_word(wAMB_TEMP) * 1000 / 256;
> +	} else if (attr == BAT_INFO_CHARGE_PCT) {
> +		*result = read_ec_byte(SOC);
> +	} else 
> +		ret = -EINVAL;
> +
> +	unlock_ec();
> +	return ret;
> +}
> +
> +int olpc_bat_query_str(struct battery_classdev *dev, int attr, char *str, int len)
> +{
> +	int ret = 0;
> +
> +	if (attr == BAT_INFO_TYPE) {
> +		snprintf(str, len, "OLPC");
> +	} else if (attr == BAT_INFO_TEMP1_NAME) {
> +		snprintf(str, len, "battery");
> +	} else if (attr == BAT_INFO_TEMP2_NAME) {
> +		snprintf(str, len, "ambient");
> +	} else if (!(read_ec_byte(sMBAT_STATUS) & sBAT_PRESENT)) {
> +		ret = -ENODEV;
> +	} else if (attr == BAT_INFO_TECHNOLOGY) {
> +		if (lock_ec())
> +			ret = -EIO;
> +		else {
> +			unsigned short tmp = read_ec_byte(sMCHARGE_STATUS);
> +			if (tmp & sBAT_NiMH)
> +				snprintf(str, len, "NiMH");
> +			else
> +				snprintf(str, len, "unknown");
> +		}
> +		unlock_ec();
> +	} else {
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
> +static struct battery_classdev olpc_bat = {
> +	.name = "OLPC",
> +	.capabilities = (1<<BAT_INFO_VOLTAGE) |
> +			(1<<BAT_INFO_CURRENT) |
> +			(1<<BAT_INFO_TEMP1) |
> +			(1<<BAT_INFO_TEMP2) |
> +			(1<<BAT_INFO_CHARGE_PCT) |
> +			(1<<BAT_INFO_TYPE) |
> +			(1<<BAT_INFO_TECHNOLOGY) |
> +			(1<<BAT_INFO_TEMP1_NAME) |
> +			(1<<BAT_INFO_TEMP2_NAME),
> +	.status_cap = BAT_STAT_AC | BAT_STAT_PRESENT | BAT_STAT_LOW | 
> +		      BAT_STAT_FULL | BAT_STAT_CHARGING| BAT_STAT_DISCHARGING |
> +		      BAT_STAT_OVERTEMP | BAT_STAT_FIRE,
> +	.status = olpc_bat_status,
> +	.query_long = olpc_bat_query_long,
> +	.query_str = olpc_bat_query_str,
> +};
> +
> +void __exit olpc_bat_exit(void)
> +{
> +	battery_classdev_unregister(&olpc_bat);
> +}
> +
> +int __init olpc_bat_init(void)
> +{
> +	battery_classdev_register(NULL, &olpc_bat);
> +	return 0;
> +}
> +
> +module_init(olpc_bat_init);
> +module_exit(olpc_bat_exit);
> +
> +MODULE_AUTHOR("David Woodhouse <dwmw2 at infradead.org>");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Battery class interface");
> --- /dev/null	2006-10-01 17:20:05.827666723 +0100
> +++ include/linux/battery.h	2006-10-23 17:11:28.000000000 +0100
> @@ -0,0 +1,84 @@
> +/*
> + * Driver model for batteries
> + *
> + *	© 2006 David Woodhouse <dwmw2 at infradead.org>
> + *
> + * Based on LED Class support, by John Lenz and Richard Purdie:
> + *
> + *	© 2005 John Lenz <lenz at cs.wisc.edu>
> + *	© 2005-2006 Richard Purdie <rpurdie at openedhand.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +#ifndef __LINUX_BATTERY_H__
> +#define __LINUX_BATTERY_H__
> +
> +struct device;
> +struct class_device;
> +
> +/*
> + * Battery Core
> + */
> +#define BAT_STAT_AC		(1<<0)
> +#define BAT_STAT_PRESENT	(1<<1)
> +#define BAT_STAT_LOW		(1<<2)
> +#define BAT_STAT_FULL		(1<<3)
> +#define BAT_STAT_CHARGING	(1<<4)
> +#define BAT_STAT_DISCHARGING	(1<<5)
> +#define BAT_STAT_OVERTEMP	(1<<6)
> +#define BAT_STAT_FIRE		(1<<7)
> +#define BAT_STAT_CHARGE_DONE	(1<<8)
> +
> +#define BAT_STAT_ERROR		(1<<31)
> +
> +#define BAT_INFO_TEMP1		(0) /* °C/1000 */
> +#define BAT_INFO_TEMP1_NAME	(1) /* string */
> +
> +#define BAT_INFO_TEMP2		(2) /* °C/1000 */
> +#define BAT_INFO_TEMP2_NAME	(3) /* string */
> +
> +#define BAT_INFO_VOLTAGE	(4) /* mV */
> +#define BAT_INFO_VOLTAGE_DESIGN	(5) /* mV */
> +
> +#define BAT_INFO_CURRENT	(6) /* mA */
> +
> +#define BAT_INFO_CHARGE_RATE	(7) /* BAT_INFO_CHARGE_UNITS */
> +#define BAT_INFO_CHARGE		(8) /* BAT_INFO_CHARGE_UNITS */
> +#define BAT_INFO_CHARGE_MAX	(9) /* BAT_INFO_CHARGE_UNITS  */
> +#define BAT_INFO_CHARGE_LAST	(10) /* BAT_INFO_CHARGE_UNITS  */
> +#define BAT_INFO_CHARGE_LOW	(11) /* BAT_INFO_CHARGE_UNITS  */
> +#define BAT_INFO_CHARGE_WARN	(12) /* BAT_INFO_CHARGE_UNITS  */
> +#define BAT_INFO_CHARGE_UNITS	(13) /* string */
> +#define BAT_INFO_CHARGE_PCT	(14) /* % */
> +
> +#define BAT_INFO_TIME_REMAINING	(15) /* seconds */
> +
> +#define BAT_INFO_MANUFACTURER	(16) /* string */
> +#define BAT_INFO_TECHNOLOGY	(17) /* string */
> +#define BAT_INFO_MODEL		(18) /* string */
> +#define BAT_INFO_SERIAL		(19) /* string */
> +#define BAT_INFO_TYPE		(20) /* string */
> +#define BAT_INFO_OEM_INFO	(21) /* string */
> +
> +struct battery_classdev {
> +	const char		*name;
> +	/* Capabilities of this battery driver */
> +	unsigned long		 capabilities, status_cap;
> +
> +	/* Query functions */
> +	unsigned long		(*status)(struct battery_classdev *, unsigned long mask);
> +	int			(*query_long)(struct battery_classdev *, int attr, long *result);
> +	int			(*query_str)(struct battery_classdev *, int attr, char *str, ssize_t len);
> +
> +	struct class_device	*class_dev;
> +	struct list_head	 node;	/* Battery Device list */
> +};
> +
> +extern int battery_classdev_register(struct device *parent,
> +				     struct battery_classdev *battery_cdev);
> +extern void battery_classdev_unregister(struct battery_classdev *battery_cdev);
> +
> +#endif /* __LINUX_BATTERY_H__ */
> 
> 
> -- 
> dwmw2
> _______________________________________________
> Devel mailing list
> Devel at laptop.org
> http://mailman.laptop.org/mailman/listinfo/devel




More information about the Devel mailing list