2005-04-17 02:20:36 +04:00
/*
2007-09-26 19:42:58 +04:00
* battery . c - ACPI Battery Driver ( Revision : 2.0 )
2005-04-17 02:20:36 +04:00
*
2007-09-26 19:42:58 +04:00
* Copyright ( C ) 2007 Alexey Starikovskiy < astarikovskiy @ suse . de >
* Copyright ( C ) 2004 - 2007 Vladimir Lebedev < vladimir . p . lebedev @ intel . com >
2005-04-17 02:20:36 +04:00
* Copyright ( C ) 2001 , 2002 Andy Grover < andrew . grover @ intel . com >
* Copyright ( C ) 2001 , 2002 Paul Diefenbaugh < paul . s . diefenbaugh @ intel . com >
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* 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/types.h>
2007-09-26 19:42:52 +04:00
# include <linux/jiffies.h>
2007-09-26 19:43:04 +04:00
# ifdef CONFIG_ACPI_PROCFS
2005-04-17 02:20:36 +04:00
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
# include <asm/uaccess.h>
2007-09-26 19:43:04 +04:00
# endif
2005-04-17 02:20:36 +04:00
# include <acpi/acpi_bus.h>
# include <acpi/acpi_drivers.h>
2007-09-26 19:43:04 +04:00
# include <linux/power_supply.h>
2005-04-17 02:20:36 +04:00
# define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
# define ACPI_BATTERY_COMPONENT 0x00040000
# define ACPI_BATTERY_CLASS "battery"
# define ACPI_BATTERY_DEVICE_NAME "Battery"
# define ACPI_BATTERY_NOTIFY_STATUS 0x80
# define ACPI_BATTERY_NOTIFY_INFO 0x81
# define _COMPONENT ACPI_BATTERY_COMPONENT
2007-02-20 15:48:06 +03:00
2007-02-13 06:42:12 +03:00
ACPI_MODULE_NAME ( " battery " ) ;
2005-04-17 02:20:36 +04:00
2007-02-13 06:42:12 +03:00
MODULE_AUTHOR ( " Paul Diefenbaugh " ) ;
2007-09-26 19:42:58 +04:00
MODULE_AUTHOR ( " Alexey Starikovskiy <astarikovskiy@suse.de> " ) ;
2007-02-13 07:50:02 +03:00
MODULE_DESCRIPTION ( " ACPI Battery Driver " ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;
2007-09-26 19:42:52 +04:00
static unsigned int cache_time = 1000 ;
module_param ( cache_time , uint , 0644 ) ;
MODULE_PARM_DESC ( cache_time , " cache time in milliseconds " ) ;
2007-02-20 15:48:06 +03:00
2007-09-26 19:43:04 +04:00
# ifdef CONFIG_ACPI_PROCFS
2006-07-01 19:36:54 +04:00
extern struct proc_dir_entry * acpi_lock_battery_dir ( void ) ;
extern void * acpi_unlock_battery_dir ( struct proc_dir_entry * acpi_battery_dir ) ;
2007-09-26 19:43:04 +04:00
enum acpi_battery_files {
info_tag = 0 ,
state_tag ,
alarm_tag ,
ACPI_BATTERY_NUMFILES ,
} ;
# endif
2007-07-23 16:44:41 +04:00
static const struct acpi_device_id battery_device_ids [ ] = {
{ " PNP0C0A " , 0 } ,
{ " " , 0 } ,
} ;
2007-09-26 19:42:58 +04:00
MODULE_DEVICE_TABLE ( acpi , battery_device_ids ) ;
2005-04-17 02:20:36 +04:00
2007-05-11 21:18:55 +04:00
2005-04-17 02:20:36 +04:00
struct acpi_battery {
2007-09-26 19:42:46 +04:00
struct mutex lock ;
2007-09-26 19:43:04 +04:00
struct power_supply bat ;
2007-09-26 19:42:52 +04:00
struct acpi_device * device ;
unsigned long update_time ;
2007-09-26 19:43:04 +04:00
int current_now ;
int capacity_now ;
int voltage_now ;
2007-09-26 19:42:46 +04:00
int design_capacity ;
2007-09-26 19:43:04 +04:00
int full_charge_capacity ;
2007-09-26 19:42:46 +04:00
int technology ;
int design_voltage ;
int design_capacity_warning ;
int design_capacity_low ;
int capacity_granularity_1 ;
int capacity_granularity_2 ;
2007-09-26 19:42:52 +04:00
int alarm ;
2007-09-26 19:42:46 +04:00
char model_number [ 32 ] ;
char serial_number [ 32 ] ;
char type [ 32 ] ;
char oem_info [ 32 ] ;
2007-09-26 19:42:52 +04:00
int state ;
int power_unit ;
2007-09-26 19:42:46 +04:00
u8 alarm_present ;
2005-04-17 02:20:36 +04:00
} ;
2007-09-26 19:43:04 +04:00
# define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);
2007-05-11 21:18:55 +04:00
inline int acpi_battery_present ( struct acpi_battery * battery )
2007-02-20 15:48:06 +03:00
{
2007-05-11 21:18:55 +04:00
return battery - > device - > status . battery_present ;
}
2007-09-26 19:42:46 +04:00
2007-09-26 19:43:04 +04:00
static int acpi_battery_technology ( struct acpi_battery * battery )
{
if ( ! strcasecmp ( " NiCd " , battery - > type ) )
return POWER_SUPPLY_TECHNOLOGY_NiCd ;
if ( ! strcasecmp ( " NiMH " , battery - > type ) )
return POWER_SUPPLY_TECHNOLOGY_NiMH ;
if ( ! strcasecmp ( " LION " , battery - > type ) )
return POWER_SUPPLY_TECHNOLOGY_LION ;
if ( ! strcasecmp ( " LiP " , battery - > type ) )
return POWER_SUPPLY_TECHNOLOGY_LIPO ;
return POWER_SUPPLY_TECHNOLOGY_UNKNOWN ;
}
static int acpi_battery_get_property ( struct power_supply * psy ,
enum power_supply_property psp ,
union power_supply_propval * val )
{
struct acpi_battery * battery = to_acpi_battery ( psy ) ;
if ( ( ! acpi_battery_present ( battery ) ) & &
psp ! = POWER_SUPPLY_PROP_PRESENT )
return - ENODEV ;
switch ( psp ) {
case POWER_SUPPLY_PROP_STATUS :
if ( battery - > state & 0x01 )
val - > intval = POWER_SUPPLY_STATUS_DISCHARGING ;
else if ( battery - > state & 0x02 )
val - > intval = POWER_SUPPLY_STATUS_CHARGING ;
else if ( battery - > state = = 0 )
val - > intval = POWER_SUPPLY_STATUS_FULL ;
break ;
case POWER_SUPPLY_PROP_PRESENT :
val - > intval = acpi_battery_present ( battery ) ;
break ;
case POWER_SUPPLY_PROP_TECHNOLOGY :
val - > intval = acpi_battery_technology ( battery ) ;
break ;
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN :
val - > intval = battery - > design_voltage * 1000 ;
break ;
case POWER_SUPPLY_PROP_VOLTAGE_NOW :
val - > intval = battery - > voltage_now * 1000 ;
break ;
case POWER_SUPPLY_PROP_CURRENT_NOW :
val - > intval = battery - > current_now * 1000 ;
break ;
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN :
case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN :
val - > intval = battery - > design_capacity * 1000 ;
break ;
case POWER_SUPPLY_PROP_CHARGE_FULL :
case POWER_SUPPLY_PROP_ENERGY_FULL :
val - > intval = battery - > full_charge_capacity * 1000 ;
break ;
case POWER_SUPPLY_PROP_CHARGE_NOW :
case POWER_SUPPLY_PROP_ENERGY_NOW :
val - > intval = battery - > capacity_now * 1000 ;
break ;
case POWER_SUPPLY_PROP_MODEL_NAME :
val - > strval = battery - > model_number ;
break ;
case POWER_SUPPLY_PROP_MANUFACTURER :
val - > strval = battery - > oem_info ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
static enum power_supply_property charge_battery_props [ ] = {
POWER_SUPPLY_PROP_STATUS ,
POWER_SUPPLY_PROP_PRESENT ,
POWER_SUPPLY_PROP_TECHNOLOGY ,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN ,
POWER_SUPPLY_PROP_VOLTAGE_NOW ,
POWER_SUPPLY_PROP_CURRENT_NOW ,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN ,
POWER_SUPPLY_PROP_CHARGE_FULL ,
POWER_SUPPLY_PROP_CHARGE_NOW ,
POWER_SUPPLY_PROP_MODEL_NAME ,
POWER_SUPPLY_PROP_MANUFACTURER ,
} ;
static enum power_supply_property energy_battery_props [ ] = {
POWER_SUPPLY_PROP_STATUS ,
POWER_SUPPLY_PROP_PRESENT ,
POWER_SUPPLY_PROP_TECHNOLOGY ,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN ,
POWER_SUPPLY_PROP_VOLTAGE_NOW ,
POWER_SUPPLY_PROP_CURRENT_NOW ,
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN ,
POWER_SUPPLY_PROP_ENERGY_FULL ,
POWER_SUPPLY_PROP_ENERGY_NOW ,
POWER_SUPPLY_PROP_MODEL_NAME ,
POWER_SUPPLY_PROP_MANUFACTURER ,
} ;
# ifdef CONFIG_ACPI_PROCFS
2007-09-26 19:42:52 +04:00
inline char * acpi_battery_units ( struct acpi_battery * battery )
2007-05-11 21:18:55 +04:00
{
2007-09-26 19:42:52 +04:00
return ( battery - > power_unit ) ? " mA " : " mW " ;
2007-02-20 15:48:06 +03:00
}
2007-09-26 19:43:04 +04:00
# endif
2007-02-20 15:48:06 +03:00
2007-05-11 21:18:55 +04:00
/* --------------------------------------------------------------------------
Battery Management
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-09-26 19:42:46 +04:00
struct acpi_offsets {
size_t offset ; /* offset inside struct acpi_sbs_battery */
u8 mode ; /* int or string? */
} ;
2007-02-20 15:48:06 +03:00
2007-09-26 19:42:46 +04:00
static struct acpi_offsets state_offsets [ ] = {
{ offsetof ( struct acpi_battery , state ) , 0 } ,
2007-09-26 19:43:04 +04:00
{ offsetof ( struct acpi_battery , current_now ) , 0 } ,
{ offsetof ( struct acpi_battery , capacity_now ) , 0 } ,
{ offsetof ( struct acpi_battery , voltage_now ) , 0 } ,
2007-09-26 19:42:46 +04:00
} ;
2007-02-20 15:48:06 +03:00
2007-09-26 19:42:46 +04:00
static struct acpi_offsets info_offsets [ ] = {
{ offsetof ( struct acpi_battery , power_unit ) , 0 } ,
{ offsetof ( struct acpi_battery , design_capacity ) , 0 } ,
2007-09-26 19:43:04 +04:00
{ offsetof ( struct acpi_battery , full_charge_capacity ) , 0 } ,
2007-09-26 19:42:46 +04:00
{ offsetof ( struct acpi_battery , technology ) , 0 } ,
{ offsetof ( struct acpi_battery , design_voltage ) , 0 } ,
{ offsetof ( struct acpi_battery , design_capacity_warning ) , 0 } ,
{ offsetof ( struct acpi_battery , design_capacity_low ) , 0 } ,
{ offsetof ( struct acpi_battery , capacity_granularity_1 ) , 0 } ,
{ offsetof ( struct acpi_battery , capacity_granularity_2 ) , 0 } ,
{ offsetof ( struct acpi_battery , model_number ) , 1 } ,
{ offsetof ( struct acpi_battery , serial_number ) , 1 } ,
{ offsetof ( struct acpi_battery , type ) , 1 } ,
{ offsetof ( struct acpi_battery , oem_info ) , 1 } ,
} ;
2007-02-20 15:48:06 +03:00
2007-09-26 19:42:46 +04:00
static int extract_package ( struct acpi_battery * battery ,
union acpi_object * package ,
struct acpi_offsets * offsets , int num )
{
int i , * x ;
union acpi_object * element ;
if ( package - > type ! = ACPI_TYPE_PACKAGE )
return - EFAULT ;
for ( i = 0 ; i < num ; + + i ) {
if ( package - > package . count < = i )
return - EFAULT ;
element = & package - > package . elements [ i ] ;
if ( offsets [ i ] . mode ) {
if ( element - > type ! = ACPI_TYPE_STRING & &
element - > type ! = ACPI_TYPE_BUFFER )
return - EFAULT ;
strncpy ( ( u8 * ) battery + offsets [ i ] . offset ,
element - > string . pointer , 32 ) ;
} else {
if ( element - > type ! = ACPI_TYPE_INTEGER )
return - EFAULT ;
x = ( int * ) ( ( u8 * ) battery + offsets [ i ] . offset ) ;
* x = element - > integer . value ;
}
2007-02-20 15:48:06 +03:00
}
return 0 ;
}
static int acpi_battery_get_status ( struct acpi_battery * battery )
{
2007-09-26 19:42:58 +04:00
if ( acpi_bus_get_status ( battery - > device ) ) {
2007-02-20 15:48:06 +03:00
ACPI_EXCEPTION ( ( AE_INFO , AE_ERROR , " Evaluating _STA " ) ) ;
return - ENODEV ;
}
2007-09-26 19:42:58 +04:00
return 0 ;
2007-02-20 15:48:06 +03:00
}
static int acpi_battery_get_info ( struct acpi_battery * battery )
2005-04-17 02:20:36 +04:00
{
2007-09-26 19:42:58 +04:00
int result = - EFAULT ;
2005-08-05 08:44:28 +04:00
acpi_status status = 0 ;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
2005-04-17 02:20:36 +04:00
2007-02-20 15:48:06 +03:00
if ( ! acpi_battery_present ( battery ) )
return 0 ;
2007-09-26 19:42:46 +04:00
mutex_lock ( & battery - > lock ) ;
2007-09-26 19:42:52 +04:00
status = acpi_evaluate_object ( battery - > device - > handle , " _BIF " ,
2007-09-26 19:42:46 +04:00
NULL , & buffer ) ;
mutex_unlock ( & battery - > lock ) ;
2007-09-26 19:42:58 +04:00
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) ) {
2006-06-27 07:58:43 +04:00
ACPI_EXCEPTION ( ( AE_INFO , status , " Evaluating _BIF " ) ) ;
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2007-09-26 19:42:58 +04:00
2007-09-26 19:42:46 +04:00
result = extract_package ( battery , buffer . pointer ,
info_offsets , ARRAY_SIZE ( info_offsets ) ) ;
2007-05-11 21:18:55 +04:00
kfree ( buffer . pointer ) ;
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
2007-02-20 15:48:06 +03:00
static int acpi_battery_get_state ( struct acpi_battery * battery )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
acpi_status status = 0 ;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
2005-04-17 02:20:36 +04:00
2007-02-20 15:48:06 +03:00
if ( ! acpi_battery_present ( battery ) )
return 0 ;
2005-04-17 02:20:36 +04:00
2007-09-26 19:42:52 +04:00
if ( battery - > update_time & &
time_before ( jiffies , battery - > update_time +
msecs_to_jiffies ( cache_time ) ) )
return 0 ;
2007-09-26 19:42:46 +04:00
mutex_lock ( & battery - > lock ) ;
2007-09-26 19:42:52 +04:00
status = acpi_evaluate_object ( battery - > device - > handle , " _BST " ,
2007-09-26 19:42:46 +04:00
NULL , & buffer ) ;
mutex_unlock ( & battery - > lock ) ;
2007-08-15 08:19:26 +04:00
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) ) {
2006-06-27 07:58:43 +04:00
ACPI_EXCEPTION ( ( AE_INFO , status , " Evaluating _BST " ) ) ;
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2007-09-26 19:42:58 +04:00
2007-09-26 19:42:46 +04:00
result = extract_package ( battery , buffer . pointer ,
state_offsets , ARRAY_SIZE ( state_offsets ) ) ;
2007-09-26 19:42:52 +04:00
battery - > update_time = jiffies ;
2007-05-11 21:18:55 +04:00
kfree ( buffer . pointer ) ;
2007-02-20 15:48:06 +03:00
return result ;
}
2005-04-17 02:20:36 +04:00
2007-09-26 19:42:58 +04:00
static int acpi_battery_set_alarm ( struct acpi_battery * battery )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = 0 ;
2007-09-26 19:42:58 +04:00
union acpi_object arg0 = { . type = ACPI_TYPE_INTEGER } ;
2005-08-05 08:44:28 +04:00
struct acpi_object_list arg_list = { 1 , & arg0 } ;
2005-04-17 02:20:36 +04:00
2007-09-26 19:42:58 +04:00
if ( ! acpi_battery_present ( battery ) | | ! battery - > alarm_present )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2007-09-26 19:42:58 +04:00
arg0 . integer . value = battery - > alarm ;
2005-04-17 02:20:36 +04:00
2007-09-26 19:42:46 +04:00
mutex_lock ( & battery - > lock ) ;
2007-09-26 19:42:52 +04:00
status = acpi_evaluate_object ( battery - > device - > handle , " _BTP " ,
& arg_list , NULL ) ;
2007-09-26 19:42:46 +04:00
mutex_unlock ( & battery - > lock ) ;
2007-09-26 19:42:58 +04:00
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2007-09-26 19:42:58 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Alarm set to %d \n " , battery - > alarm ) ) ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-02-20 15:48:06 +03:00
static int acpi_battery_init_alarm ( struct acpi_battery * battery )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = AE_OK ;
acpi_handle handle = NULL ;
2007-02-20 15:48:06 +03:00
/* See if alarms are supported, and if so, set default */
2007-09-26 19:42:52 +04:00
status = acpi_get_handle ( battery - > device - > handle , " _BTP " , & handle ) ;
if ( ACPI_FAILURE ( status ) ) {
2007-09-26 19:42:46 +04:00
battery - > alarm_present = 0 ;
2007-09-26 19:42:52 +04:00
return 0 ;
2007-02-20 15:48:06 +03:00
}
2007-09-26 19:42:52 +04:00
battery - > alarm_present = 1 ;
if ( ! battery - > alarm )
battery - > alarm = battery - > design_capacity_warning ;
2007-09-26 19:42:58 +04:00
return acpi_battery_set_alarm ( battery ) ;
2007-02-20 15:48:06 +03:00
}
2005-04-17 02:20:36 +04:00
2007-09-26 19:42:52 +04:00
static int acpi_battery_update ( struct acpi_battery * battery )
2007-02-20 15:48:06 +03:00
{
2007-09-26 19:42:52 +04:00
int saved_present = acpi_battery_present ( battery ) ;
int result = acpi_battery_get_status ( battery ) ;
if ( result | | ! acpi_battery_present ( battery ) )
2007-02-20 15:48:06 +03:00
return result ;
2007-09-26 19:42:52 +04:00
if ( saved_present ! = acpi_battery_present ( battery ) | |
! battery - > update_time ) {
battery - > update_time = 0 ;
2007-02-20 15:48:06 +03:00
result = acpi_battery_get_info ( battery ) ;
if ( result )
return result ;
2007-09-26 19:43:04 +04:00
if ( battery - > power_unit ) {
battery - > bat . properties = charge_battery_props ;
battery - > bat . num_properties =
ARRAY_SIZE ( charge_battery_props ) ;
} else {
battery - > bat . properties = energy_battery_props ;
battery - > bat . num_properties =
ARRAY_SIZE ( energy_battery_props ) ;
}
2007-02-20 15:48:06 +03:00
acpi_battery_init_alarm ( battery ) ;
}
2007-09-26 19:42:52 +04:00
return acpi_battery_get_state ( battery ) ;
2007-02-10 09:43:48 +03:00
}
2005-04-17 02:20:36 +04:00
/* --------------------------------------------------------------------------
FS Interface ( / proc )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-09-26 19:43:04 +04:00
# ifdef CONFIG_ACPI_PROCFS
2005-08-05 08:44:28 +04:00
static struct proc_dir_entry * acpi_battery_dir ;
2007-02-20 15:48:06 +03:00
2007-05-11 21:18:55 +04:00
static int acpi_battery_print_info ( struct seq_file * seq , int result )
2005-04-17 02:20:36 +04:00
{
2006-10-01 02:28:50 +04:00
struct acpi_battery * battery = seq - > private ;
2005-04-17 02:20:36 +04:00
2007-02-20 15:48:06 +03:00
if ( result )
2005-04-17 02:20:36 +04:00
goto end ;
2007-09-26 19:42:58 +04:00
seq_printf ( seq , " present: %s \n " ,
acpi_battery_present ( battery ) ? " yes " : " no " ) ;
if ( ! acpi_battery_present ( battery ) )
2005-04-17 02:20:36 +04:00
goto end ;
2007-09-26 19:42:46 +04:00
if ( battery - > design_capacity = = ACPI_BATTERY_VALUE_UNKNOWN )
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " design capacity: unknown \n " ) ;
else
seq_printf ( seq , " design capacity: %d %sh \n " ,
2007-09-26 19:42:58 +04:00
battery - > design_capacity ,
acpi_battery_units ( battery ) ) ;
2005-04-17 02:20:36 +04:00
2007-09-26 19:43:04 +04:00
if ( battery - > full_charge_capacity = = ACPI_BATTERY_VALUE_UNKNOWN )
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " last full capacity: unknown \n " ) ;
else
seq_printf ( seq , " last full capacity: %d %sh \n " ,
2007-09-26 19:43:04 +04:00
battery - > full_charge_capacity ,
2007-09-26 19:42:58 +04:00
acpi_battery_units ( battery ) ) ;
seq_printf ( seq , " battery technology: %srechargeable \n " ,
( ! battery - > technology ) ? " non- " : " " ) ;
2005-04-17 02:20:36 +04:00
2007-09-26 19:42:46 +04:00
if ( battery - > design_voltage = = ACPI_BATTERY_VALUE_UNKNOWN )
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " design voltage: unknown \n " ) ;
else
seq_printf ( seq , " design voltage: %d mV \n " ,
2007-09-26 19:42:58 +04:00
battery - > design_voltage ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " design capacity warning: %d %sh \n " ,
2007-09-26 19:42:58 +04:00
battery - > design_capacity_warning ,
acpi_battery_units ( battery ) ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " design capacity low: %d %sh \n " ,
2007-09-26 19:42:58 +04:00
battery - > design_capacity_low ,
acpi_battery_units ( battery ) ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " capacity granularity 1: %d %sh \n " ,
2007-09-26 19:42:58 +04:00
battery - > capacity_granularity_1 ,
acpi_battery_units ( battery ) ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " capacity granularity 2: %d %sh \n " ,
2007-09-26 19:42:58 +04:00
battery - > capacity_granularity_2 ,
acpi_battery_units ( battery ) ) ;
2007-09-26 19:42:46 +04:00
seq_printf ( seq , " model number: %s \n " , battery - > model_number ) ;
seq_printf ( seq , " serial number: %s \n " , battery - > serial_number ) ;
seq_printf ( seq , " battery type: %s \n " , battery - > type ) ;
seq_printf ( seq , " OEM info: %s \n " , battery - > oem_info ) ;
2005-08-05 08:44:28 +04:00
end :
2007-02-20 15:48:06 +03:00
if ( result )
seq_printf ( seq , " ERROR: Unable to read battery info \n " ) ;
return result ;
}
2007-05-11 21:18:55 +04:00
static int acpi_battery_print_state ( struct seq_file * seq , int result )
2005-04-17 02:20:36 +04:00
{
2006-10-01 02:28:50 +04:00
struct acpi_battery * battery = seq - > private ;
2005-04-17 02:20:36 +04:00
2007-02-20 15:48:06 +03:00
if ( result )
2005-04-17 02:20:36 +04:00
goto end ;
2007-09-26 19:42:58 +04:00
seq_printf ( seq , " present: %s \n " ,
acpi_battery_present ( battery ) ? " yes " : " no " ) ;
if ( ! acpi_battery_present ( battery ) )
2005-04-17 02:20:36 +04:00
goto end ;
2007-02-20 15:48:06 +03:00
2007-09-26 19:42:58 +04:00
seq_printf ( seq , " capacity state: %s \n " ,
( battery - > state & 0x04 ) ? " critical " : " ok " ) ;
if ( ( battery - > state & 0x01 ) & & ( battery - > state & 0x02 ) )
2005-08-05 08:44:28 +04:00
seq_printf ( seq ,
" charging state: charging/discharging \n " ) ;
2007-09-26 19:42:58 +04:00
else if ( battery - > state & 0x01 )
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " charging state: discharging \n " ) ;
2007-09-26 19:42:46 +04:00
else if ( battery - > state & 0x02 )
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " charging state: charging \n " ) ;
2007-09-26 19:42:58 +04:00
else
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " charging state: charged \n " ) ;
2007-09-26 19:43:04 +04:00
if ( battery - > current_now = = ACPI_BATTERY_VALUE_UNKNOWN )
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " present rate: unknown \n " ) ;
else
seq_printf ( seq , " present rate: %d %s \n " ,
2007-09-26 19:43:04 +04:00
battery - > current_now , acpi_battery_units ( battery ) ) ;
2005-04-17 02:20:36 +04:00
2007-09-26 19:43:04 +04:00
if ( battery - > capacity_now = = ACPI_BATTERY_VALUE_UNKNOWN )
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " remaining capacity: unknown \n " ) ;
else
seq_printf ( seq , " remaining capacity: %d %sh \n " ,
2007-09-26 19:43:04 +04:00
battery - > capacity_now , acpi_battery_units ( battery ) ) ;
if ( battery - > voltage_now = = ACPI_BATTERY_VALUE_UNKNOWN )
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " present voltage: unknown \n " ) ;
else
seq_printf ( seq , " present voltage: %d mV \n " ,
2007-09-26 19:43:04 +04:00
battery - > voltage_now ) ;
2005-08-05 08:44:28 +04:00
end :
2007-09-26 19:42:58 +04:00
if ( result )
2007-02-20 15:48:06 +03:00
seq_printf ( seq , " ERROR: Unable to read battery state \n " ) ;
return result ;
}
2007-05-11 21:18:55 +04:00
static int acpi_battery_print_alarm ( struct seq_file * seq , int result )
2005-04-17 02:20:36 +04:00
{
2006-10-01 02:28:50 +04:00
struct acpi_battery * battery = seq - > private ;
2005-04-17 02:20:36 +04:00
2007-02-20 15:48:06 +03:00
if ( result )
2005-04-17 02:20:36 +04:00
goto end ;
2007-02-20 15:48:06 +03:00
if ( ! acpi_battery_present ( battery ) ) {
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " present: no \n " ) ;
goto end ;
}
seq_printf ( seq , " alarm: " ) ;
if ( ! battery - > alarm )
seq_printf ( seq , " unsupported \n " ) ;
else
2007-09-26 19:42:58 +04:00
seq_printf ( seq , " %u %sh \n " , battery - > alarm ,
acpi_battery_units ( battery ) ) ;
2005-08-05 08:44:28 +04:00
end :
2007-02-20 15:48:06 +03:00
if ( result )
seq_printf ( seq , " ERROR: Unable to read battery alarm \n " ) ;
return result ;
}
2007-09-26 19:42:52 +04:00
static ssize_t acpi_battery_write_alarm ( struct file * file ,
const char __user * buffer ,
size_t count , loff_t * ppos )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
char alarm_string [ 12 ] = { ' \0 ' } ;
2006-10-01 02:28:50 +04:00
struct seq_file * m = file - > private_data ;
struct acpi_battery * battery = m - > private ;
2005-04-17 02:20:36 +04:00
if ( ! battery | | ( count > sizeof ( alarm_string ) - 1 ) )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2007-02-20 15:48:06 +03:00
if ( result ) {
result = - ENODEV ;
goto end ;
}
if ( ! acpi_battery_present ( battery ) ) {
result = - ENODEV ;
goto end ;
}
if ( copy_from_user ( alarm_string , buffer , count ) ) {
result = - EFAULT ;
goto end ;
}
2005-04-17 02:20:36 +04:00
alarm_string [ count ] = ' \0 ' ;
2007-09-26 19:42:52 +04:00
battery - > alarm = simple_strtol ( alarm_string , NULL , 0 ) ;
2007-09-26 19:42:58 +04:00
result = acpi_battery_set_alarm ( battery ) ;
2007-02-20 15:48:06 +03:00
end :
if ( ! result )
2007-09-26 19:42:52 +04:00
return count ;
2007-05-11 21:18:55 +04:00
return result ;
}
typedef int ( * print_func ) ( struct seq_file * seq , int result ) ;
2007-09-26 19:42:58 +04:00
static print_func acpi_print_funcs [ ACPI_BATTERY_NUMFILES ] = {
acpi_battery_print_info ,
acpi_battery_print_state ,
acpi_battery_print_alarm ,
2007-05-11 21:18:55 +04:00
} ;
2007-02-20 15:48:06 +03:00
2007-05-11 21:18:55 +04:00
static int acpi_battery_read ( int fid , struct seq_file * seq )
{
struct acpi_battery * battery = seq - > private ;
2007-09-26 19:42:52 +04:00
int result = acpi_battery_update ( battery ) ;
2007-09-26 19:42:58 +04:00
return acpi_print_funcs [ fid ] ( seq , result ) ;
2007-05-11 21:18:55 +04:00
}
2007-09-26 19:42:58 +04:00
# define DECLARE_FILE_FUNCTIONS(_name) \
static int acpi_battery_read_ # # _name ( struct seq_file * seq , void * offset ) \
{ \
return acpi_battery_read ( _name # # _tag , seq ) ; \
} \
static int acpi_battery_ # # _name # # _open_fs ( struct inode * inode , struct file * file ) \
{ \
return single_open ( file , acpi_battery_read_ # # _name , PDE ( inode ) - > data ) ; \
2007-05-11 21:18:55 +04:00
}
2007-09-26 19:42:58 +04:00
DECLARE_FILE_FUNCTIONS ( info ) ;
DECLARE_FILE_FUNCTIONS ( state ) ;
DECLARE_FILE_FUNCTIONS ( alarm ) ;
# undef DECLARE_FILE_FUNCTIONS
# define FILE_DESCRIPTION_RO(_name) \
{ \
. name = __stringify ( _name ) , \
. mode = S_IRUGO , \
. ops = { \
. open = acpi_battery_ # # _name # # _open_fs , \
. read = seq_read , \
. llseek = seq_lseek , \
. release = single_release , \
. owner = THIS_MODULE , \
} , \
}
2007-05-11 21:18:55 +04:00
2007-09-26 19:42:58 +04:00
# define FILE_DESCRIPTION_RW(_name) \
{ \
. name = __stringify ( _name ) , \
. mode = S_IFREG | S_IRUGO | S_IWUSR , \
. ops = { \
. open = acpi_battery_ # # _name # # _open_fs , \
. read = seq_read , \
. llseek = seq_lseek , \
. write = acpi_battery_write_ # # _name , \
. release = single_release , \
. owner = THIS_MODULE , \
} , \
}
2005-04-17 02:20:36 +04:00
2007-05-11 21:18:55 +04:00
static struct battery_file {
struct file_operations ops ;
mode_t mode ;
char * name ;
} acpi_battery_file [ ] = {
2007-09-26 19:42:58 +04:00
FILE_DESCRIPTION_RO ( info ) ,
FILE_DESCRIPTION_RO ( state ) ,
FILE_DESCRIPTION_RW ( alarm ) ,
2005-04-17 02:20:36 +04:00
} ;
2007-09-26 19:42:58 +04:00
# undef FILE_DESCRIPTION_RO
# undef FILE_DESCRIPTION_RW
2005-08-05 08:44:28 +04:00
static int acpi_battery_add_fs ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct proc_dir_entry * entry = NULL ;
2007-05-11 21:18:55 +04:00
int i ;
2005-04-17 02:20:36 +04:00
if ( ! acpi_device_dir ( device ) ) {
acpi_device_dir ( device ) = proc_mkdir ( acpi_device_bid ( device ) ,
2005-08-05 08:44:28 +04:00
acpi_battery_dir ) ;
2005-04-17 02:20:36 +04:00
if ( ! acpi_device_dir ( device ) )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
acpi_device_dir ( device ) - > owner = THIS_MODULE ;
}
2007-05-11 21:18:55 +04:00
for ( i = 0 ; i < ACPI_BATTERY_NUMFILES ; + + i ) {
entry = create_proc_entry ( acpi_battery_file [ i ] . name ,
acpi_battery_file [ i ] . mode , acpi_device_dir ( device ) ) ;
if ( ! entry )
return - ENODEV ;
else {
entry - > proc_fops = & acpi_battery_file [ i ] . ops ;
entry - > data = acpi_driver_data ( device ) ;
entry - > owner = THIS_MODULE ;
}
2005-04-17 02:20:36 +04:00
}
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-09-26 19:42:58 +04:00
static void acpi_battery_remove_fs ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2007-05-11 21:18:55 +04:00
int i ;
2007-09-26 19:42:58 +04:00
if ( ! acpi_device_dir ( device ) )
return ;
for ( i = 0 ; i < ACPI_BATTERY_NUMFILES ; + + i )
remove_proc_entry ( acpi_battery_file [ i ] . name ,
2005-04-17 02:20:36 +04:00
acpi_device_dir ( device ) ) ;
2007-09-26 19:42:58 +04:00
remove_proc_entry ( acpi_device_bid ( device ) , acpi_battery_dir ) ;
acpi_device_dir ( device ) = NULL ;
2005-04-17 02:20:36 +04:00
}
2007-09-26 19:43:04 +04:00
# endif
2007-09-26 19:43:11 +04:00
static ssize_t acpi_battery_alarm_show ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct acpi_battery * battery = to_acpi_battery ( dev_get_drvdata ( dev ) ) ;
return sprintf ( buf , " %d \n " , battery - > alarm * 1000 ) ;
}
static ssize_t acpi_battery_alarm_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
unsigned long x ;
struct acpi_battery * battery = to_acpi_battery ( dev_get_drvdata ( dev ) ) ;
if ( sscanf ( buf , " %ld \n " , & x ) = = 1 )
battery - > alarm = x / 1000 ;
if ( acpi_battery_present ( battery ) )
acpi_battery_set_alarm ( battery ) ;
return count ;
}
static struct device_attribute alarm_attr = {
. attr = { . name = " alarm " , . mode = 0644 , . owner = THIS_MODULE } ,
. show = acpi_battery_alarm_show ,
. store = acpi_battery_alarm_store ,
} ;
2005-04-17 02:20:36 +04:00
/* --------------------------------------------------------------------------
Driver Interface
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2005-08-05 08:44:28 +04:00
static void acpi_battery_notify ( acpi_handle handle , u32 event , void * data )
2005-04-17 02:20:36 +04:00
{
2006-10-01 02:28:50 +04:00
struct acpi_battery * battery = data ;
2007-09-26 19:42:52 +04:00
struct acpi_device * device ;
2005-04-17 02:20:36 +04:00
if ( ! battery )
2006-06-27 08:41:40 +04:00
return ;
2006-05-20 00:54:39 +04:00
device = battery - > device ;
2007-09-26 19:42:52 +04:00
acpi_battery_update ( battery ) ;
acpi_bus_generate_proc_event ( device , event ,
acpi_battery_present ( battery ) ) ;
acpi_bus_generate_netlink_event ( device - > pnp . device_class ,
device - > dev . bus_id , event ,
2007-02-20 15:48:06 +03:00
acpi_battery_present ( battery ) ) ;
2007-09-26 19:43:04 +04:00
kobject_uevent ( & battery - > bat . dev - > kobj , KOBJ_CHANGE ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_battery_add ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
acpi_status status = 0 ;
struct acpi_battery * battery = NULL ;
2005-04-17 02:20:36 +04:00
if ( ! device )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2006-12-19 23:56:11 +03:00
battery = kzalloc ( sizeof ( struct acpi_battery ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! battery )
2006-06-27 08:41:40 +04:00
return - ENOMEM ;
2006-05-20 00:54:39 +04:00
battery - > device = device ;
2005-04-17 02:20:36 +04:00
strcpy ( acpi_device_name ( device ) , ACPI_BATTERY_DEVICE_NAME ) ;
strcpy ( acpi_device_class ( device ) , ACPI_BATTERY_CLASS ) ;
acpi_driver_data ( device ) = battery ;
2007-09-26 19:42:46 +04:00
mutex_init ( & battery - > lock ) ;
2007-09-26 19:42:52 +04:00
acpi_battery_update ( battery ) ;
2007-09-26 19:43:04 +04:00
# ifdef CONFIG_ACPI_PROCFS
2005-04-17 02:20:36 +04:00
result = acpi_battery_add_fs ( device ) ;
if ( result )
goto end ;
2007-09-26 19:43:04 +04:00
# endif
battery - > bat . name = acpi_device_bid ( device ) ;
battery - > bat . type = POWER_SUPPLY_TYPE_BATTERY ;
battery - > bat . get_property = acpi_battery_get_property ;
result = power_supply_register ( & battery - > device - > dev , & battery - > bat ) ;
2007-09-26 19:43:11 +04:00
result = device_create_file ( battery - > bat . dev , & alarm_attr ) ;
2006-05-20 00:54:41 +04:00
status = acpi_install_notify_handler ( device - > handle ,
2006-06-27 12:49:00 +04:00
ACPI_ALL_NOTIFY ,
2005-08-05 08:44:28 +04:00
acpi_battery_notify , battery ) ;
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) ) {
2007-02-20 15:48:06 +03:00
ACPI_EXCEPTION ( ( AE_INFO , status , " Installing notify handler " ) ) ;
2005-04-17 02:20:36 +04:00
result = - ENODEV ;
goto end ;
}
printk ( KERN_INFO PREFIX " %s Slot [%s] (battery %s) \n " ,
2005-08-05 08:44:28 +04:00
ACPI_BATTERY_DEVICE_NAME , acpi_device_bid ( device ) ,
device - > status . battery_present ? " present " : " absent " ) ;
end :
2005-04-17 02:20:36 +04:00
if ( result ) {
2007-09-26 19:43:04 +04:00
# ifdef CONFIG_ACPI_PROCFS
2005-04-17 02:20:36 +04:00
acpi_battery_remove_fs ( device ) ;
2007-09-26 19:43:04 +04:00
# endif
2005-04-17 02:20:36 +04:00
kfree ( battery ) ;
}
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static int acpi_battery_remove ( struct acpi_device * device , int type )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = 0 ;
struct acpi_battery * battery = NULL ;
2005-04-17 02:20:36 +04:00
if ( ! device | | ! acpi_driver_data ( device ) )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2006-10-01 02:28:50 +04:00
battery = acpi_driver_data ( device ) ;
2006-05-20 00:54:41 +04:00
status = acpi_remove_notify_handler ( device - > handle ,
2006-06-27 12:49:00 +04:00
ACPI_ALL_NOTIFY ,
2005-08-05 08:44:28 +04:00
acpi_battery_notify ) ;
2007-09-26 19:43:04 +04:00
# ifdef CONFIG_ACPI_PROCFS
2005-04-17 02:20:36 +04:00
acpi_battery_remove_fs ( device ) ;
2007-09-26 19:43:04 +04:00
# endif
2007-09-26 19:43:11 +04:00
if ( battery - > bat . dev ) {
device_remove_file ( battery - > bat . dev , & alarm_attr ) ;
2007-09-26 19:43:04 +04:00
power_supply_unregister ( & battery - > bat ) ;
2007-09-26 19:43:11 +04:00
}
2007-09-26 19:42:46 +04:00
mutex_destroy ( & battery - > lock ) ;
2005-04-17 02:20:36 +04:00
kfree ( battery ) ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-10-11 01:20:41 +04:00
/* this is needed to learn about changes made in suspended state */
2006-12-07 15:56:27 +03:00
static int acpi_battery_resume ( struct acpi_device * device )
2006-10-11 01:20:41 +04:00
{
struct acpi_battery * battery ;
if ( ! device )
return - EINVAL ;
2007-09-26 19:42:52 +04:00
battery = acpi_driver_data ( device ) ;
battery - > update_time = 0 ;
2007-02-20 15:48:06 +03:00
return 0 ;
2006-10-11 01:20:41 +04:00
}
2007-09-26 19:42:58 +04:00
static struct acpi_driver acpi_battery_driver = {
. name = " battery " ,
. class = ACPI_BATTERY_CLASS ,
. ids = battery_device_ids ,
. ops = {
. add = acpi_battery_add ,
. resume = acpi_battery_resume ,
. remove = acpi_battery_remove ,
} ,
} ;
2005-08-05 08:44:28 +04:00
static int __init acpi_battery_init ( void )
2005-04-17 02:20:36 +04:00
{
2006-08-15 09:37:22 +04:00
if ( acpi_disabled )
return - ENODEV ;
2007-09-26 19:43:04 +04:00
# ifdef CONFIG_ACPI_PROCFS
2006-07-01 19:36:54 +04:00
acpi_battery_dir = acpi_lock_battery_dir ( ) ;
2005-04-17 02:20:36 +04:00
if ( ! acpi_battery_dir )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2007-09-26 19:43:04 +04:00
# endif
2007-09-26 19:42:58 +04:00
if ( acpi_bus_register_driver ( & acpi_battery_driver ) < 0 ) {
2007-09-26 19:43:04 +04:00
# ifdef CONFIG_ACPI_PROCFS
2006-07-01 19:36:54 +04:00
acpi_unlock_battery_dir ( acpi_battery_dir ) ;
2007-09-26 19:43:04 +04:00
# endif
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
static void __exit acpi_battery_exit ( void )
2005-04-17 02:20:36 +04:00
{
acpi_bus_unregister_driver ( & acpi_battery_driver ) ;
2007-09-26 19:43:04 +04:00
# ifdef CONFIG_ACPI_PROCFS
2006-07-01 19:36:54 +04:00
acpi_unlock_battery_dir ( acpi_battery_dir ) ;
2007-09-26 19:43:04 +04:00
# endif
2005-04-17 02:20:36 +04:00
}
module_init ( acpi_battery_init ) ;
module_exit ( acpi_battery_exit ) ;