lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <1161627633.19446.387.camel@pmac.infradead.org>
Date:	Mon, 23 Oct 2006 19:20:33 +0100
From:	David Woodhouse <dwmw2@...radead.org>
To:	linux-kernel@...r.kernel.org, olpc-dev@...top.org
Cc:	davidz@...hat.com, greg@...ah.com, mjg59@...f.ucam.org,
	len.brown@...el.com, sfr@...b.auug.org.au, benh@...nel.crashing.org
Subject: Battery class driver.

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@...radead.org>
Date:   Mon Oct 23 18:14:54 2006 +0100

    [BATTERY] Add support for OLPC battery
    
    Signed-off-by: David Woodhouse <dwmw2@...radead.org>

commit 6cbec3b84e3ce737b4217788841ea10a28a5e340
Author: David Woodhouse <dwmw2@...radead.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@...radead.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@...radead.org>
+ *
+ * Based on LED Class support, by John Lenz and Richard Purdie:
+ *
+ *	© 2005 John Lenz <lenz@...wisc.edu>
+ *	© 2005-2006 Richard Purdie <rpurdie@...nedhand.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@...radead.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@...radead.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@...radead.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@...radead.org>
+ *
+ * Based on LED Class support, by John Lenz and Richard Purdie:
+ *
+ *	© 2005 John Lenz <lenz@...wisc.edu>
+ *	© 2005-2006 Richard Purdie <rpurdie@...nedhand.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

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ