Commit 3f86b832 authored by Rich Townsend's avatar Rich Townsend Committed by Len Brown

ACPI: add support for Smart Battery

Most batteries today are ACPI "Control Method" batteries,
but some models ship with the older "Smart Battery"
that requires this code.

Rich Townsend and Bruno Ducrot were the original authors.
Vladimir Lebedev updated to run on latest kernel.

http://bugzilla.kernel.org/show_bug.cgi?id=3734Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 37672d4c
......@@ -352,6 +352,18 @@ config ACPI_HOTPLUG_MEMORY
If one selects "m," this driver can be loaded using the following
command:
$>modprobe acpi_memhotplug
config ACPI_SBS
tristate "Smart Battery System (EXPERIMENTAL)"
depends on X86 && I2C
depends on EXPERIMENTAL
default y
help
This driver adds support for the Smart Battery System.
Depends on I2C (Device Drivers ---> I2C support)
A "Smart Battery" is quite old and quite rare compared
to today's ACPI "Control Method" battery.
endif # ACPI
endmenu
......@@ -58,3 +58,5 @@ obj-$(CONFIG_ACPI_IBM) += ibm_acpi.o
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
obj-y += scan.o motherboard.o
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
obj-y += cm_sbs.o
obj-$(CONFIG_ACPI_SBS) += i2c_ec.o sbs.o
......@@ -50,6 +50,9 @@ ACPI_MODULE_NAME("acpi_ac")
MODULE_DESCRIPTION(ACPI_AC_DRIVER_NAME);
MODULE_LICENSE("GPL");
extern struct proc_dir_entry *acpi_lock_ac_dir(void);
extern void *acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
static int acpi_ac_add(struct acpi_device *device);
static int acpi_ac_remove(struct acpi_device *device, int type);
static int acpi_ac_open_fs(struct inode *inode, struct file *file);
......@@ -278,17 +281,16 @@ static int acpi_ac_remove(struct acpi_device *device, int type)
static int __init acpi_ac_init(void)
{
int result = 0;
int result;
acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir);
acpi_ac_dir = acpi_lock_ac_dir();
if (!acpi_ac_dir)
return -ENODEV;
acpi_ac_dir->owner = THIS_MODULE;
result = acpi_bus_register_driver(&acpi_ac_driver);
if (result < 0) {
remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
acpi_unlock_ac_dir(acpi_ac_dir);
return -ENODEV;
}
......@@ -300,7 +302,7 @@ static void __exit acpi_ac_exit(void)
acpi_bus_unregister_driver(&acpi_ac_driver);
remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
acpi_unlock_ac_dir(acpi_ac_dir);
return;
}
......
......@@ -59,6 +59,9 @@ ACPI_MODULE_NAME("acpi_battery")
MODULE_DESCRIPTION(ACPI_BATTERY_DRIVER_NAME);
MODULE_LICENSE("GPL");
extern struct proc_dir_entry *acpi_lock_battery_dir(void);
extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
static int acpi_battery_add(struct acpi_device *device);
static int acpi_battery_remove(struct acpi_device *device, int type);
......@@ -750,17 +753,15 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
static int __init acpi_battery_init(void)
{
int result = 0;
int result;
acpi_battery_dir = proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir);
acpi_battery_dir = acpi_lock_battery_dir();
if (!acpi_battery_dir)
return -ENODEV;
acpi_battery_dir->owner = THIS_MODULE;
result = acpi_bus_register_driver(&acpi_battery_driver);
if (result < 0) {
remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);
acpi_unlock_battery_dir(acpi_battery_dir);
return -ENODEV;
}
......@@ -772,7 +773,7 @@ static void __exit acpi_battery_exit(void)
acpi_bus_unregister_driver(&acpi_battery_driver);
remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);
acpi_unlock_battery_dir(acpi_battery_dir);
return;
}
......
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acmacros.h>
#include <acpi/actypes.h>
#include <acpi/acutils.h>
ACPI_MODULE_NAME("cm_sbs")
#define ACPI_AC_CLASS "ac_adapter"
#define ACPI_BATTERY_CLASS "battery"
#define ACPI_SBS_COMPONENT 0x00080000
#define _COMPONENT ACPI_SBS_COMPONENT
static struct proc_dir_entry *acpi_ac_dir;
static struct proc_dir_entry *acpi_battery_dir;
static struct semaphore cm_sbs_sem;
static int lock_ac_dir_cnt = 0;
static int lock_battery_dir_cnt = 0;
struct proc_dir_entry *acpi_lock_ac_dir(void)
{
ACPI_FUNCTION_TRACE("acpi_lock_ac_dir");
down(&cm_sbs_sem);
if (!acpi_ac_dir) {
acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir);
}
if (acpi_ac_dir) {
lock_ac_dir_cnt++;
} else {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Cannot create %s\n", ACPI_AC_CLASS));
}
up(&cm_sbs_sem);
return (acpi_ac_dir);
}
EXPORT_SYMBOL(acpi_lock_ac_dir);
void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir_param)
{
ACPI_FUNCTION_TRACE("acpi_unlock_ac_dir");
down(&cm_sbs_sem);
if (acpi_ac_dir_param) {
lock_ac_dir_cnt--;
}
if (lock_ac_dir_cnt == 0 && acpi_ac_dir_param && acpi_ac_dir) {
remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
acpi_ac_dir = 0;
}
up(&cm_sbs_sem);
}
EXPORT_SYMBOL(acpi_unlock_ac_dir);
struct proc_dir_entry *acpi_lock_battery_dir(void)
{
ACPI_FUNCTION_TRACE("acpi_lock_battery_dir");
down(&cm_sbs_sem);
if (!acpi_battery_dir) {
acpi_battery_dir =
proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir);
}
if (acpi_battery_dir) {
lock_battery_dir_cnt++;
} else {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Cannot create %s\n", ACPI_BATTERY_CLASS));
}
up(&cm_sbs_sem);
return (acpi_battery_dir);
}
EXPORT_SYMBOL(acpi_lock_battery_dir);
void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir_param)
{
ACPI_FUNCTION_TRACE("acpi_unlock_battery_dir");
down(&cm_sbs_sem);
if (acpi_battery_dir_param) {
lock_battery_dir_cnt--;
}
if (lock_battery_dir_cnt == 0 && acpi_battery_dir_param
&& acpi_battery_dir) {
remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);
acpi_battery_dir = 0;
}
up(&cm_sbs_sem);
}
EXPORT_SYMBOL(acpi_unlock_battery_dir);
static int __init acpi_cm_sbs_init(void)
{
ACPI_FUNCTION_TRACE("acpi_cm_sbs_init");
if (acpi_disabled)
return_VALUE(0);
init_MUTEX(&cm_sbs_sem);
return_VALUE(0);
}
subsys_initcall(acpi_cm_sbs_init);
This diff is collapsed.
/*
* SMBus driver for ACPI Embedded Controller ($Revision: 1.2 $)
*
* Copyright (c) 2002, 2005 Ducrot Bruno
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2.
*/
struct acpi_ec_smbus {
struct i2c_adapter adapter;
union acpi_ec *ec;
int base;
int alert;
};
struct acpi_ec_hc {
acpi_handle handle;
struct acpi_ec_smbus *smbus;
};
struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device);
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment