[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <1161631091.16366.0.camel@localhost.localdomain>
Date: Mon, 23 Oct 2006 15:18:11 -0400
From: Dan Williams <dcbw@...hat.com>
To: David Woodhouse <dwmw2@...radead.org>
Cc: linux-kernel@...r.kernel.org, devel@...top.org,
sfr@...b.auug.org.au, len.brown@...el.com, greg@...ah.com,
benh@...nel.crashing.org, David Zeuthen <davidz@...hat.com>,
Richard Hughes <hughsient@...il.com>
Subject: Re: Battery class driver.
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@...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
> _______________________________________________
> Devel mailing list
> Devel@...top.org
> http://mailman.laptop.org/mailman/listinfo/devel
-
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