2005-04-17 02:20:36 +04:00
/*
* acpi_battery . c - ACPI Battery Driver ( $ Revision : 37 $ )
*
* 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>
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
# include <asm/uaccess.h>
# include <acpi/acpi_bus.h>
# include <acpi/acpi_drivers.h>
# define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
# define ACPI_BATTERY_FORMAT_BIF "NNNNNNNNNSSSS"
# define ACPI_BATTERY_FORMAT_BST "NNNN"
# define ACPI_BATTERY_COMPONENT 0x00040000
# define ACPI_BATTERY_CLASS "battery"
# define ACPI_BATTERY_HID "PNP0C0A"
# define ACPI_BATTERY_DRIVER_NAME "ACPI Battery Driver"
# define ACPI_BATTERY_DEVICE_NAME "Battery"
# define ACPI_BATTERY_FILE_INFO "info"
# define ACPI_BATTERY_FILE_STATUS "state"
# define ACPI_BATTERY_FILE_ALARM "alarm"
# define ACPI_BATTERY_NOTIFY_STATUS 0x80
# define ACPI_BATTERY_NOTIFY_INFO 0x81
# define ACPI_BATTERY_UNITS_WATTS "mW"
# define ACPI_BATTERY_UNITS_AMPS "mA"
# define _COMPONENT ACPI_BATTERY_COMPONENT
2005-08-05 08:44:28 +04:00
ACPI_MODULE_NAME ( " acpi_battery " )
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
MODULE_AUTHOR ( " Paul Diefenbaugh " ) ;
2005-04-17 02:20:36 +04:00
MODULE_DESCRIPTION ( ACPI_BATTERY_DRIVER_NAME ) ;
MODULE_LICENSE ( " GPL " ) ;
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 ) ;
2005-08-05 08:44:28 +04:00
static int acpi_battery_add ( struct acpi_device * device ) ;
static int acpi_battery_remove ( struct acpi_device * device , int type ) ;
2005-04-17 02:20:36 +04:00
static struct acpi_driver acpi_battery_driver = {
2005-08-05 08:44:28 +04:00
. name = ACPI_BATTERY_DRIVER_NAME ,
. class = ACPI_BATTERY_CLASS ,
. ids = ACPI_BATTERY_HID ,
. ops = {
. add = acpi_battery_add ,
. remove = acpi_battery_remove ,
} ,
2005-04-17 02:20:36 +04:00
} ;
struct acpi_battery_status {
2005-08-05 08:44:28 +04:00
acpi_integer state ;
acpi_integer present_rate ;
acpi_integer remaining_capacity ;
acpi_integer present_voltage ;
2005-04-17 02:20:36 +04:00
} ;
struct acpi_battery_info {
2005-08-05 08:44:28 +04:00
acpi_integer power_unit ;
acpi_integer design_capacity ;
acpi_integer last_full_capacity ;
acpi_integer battery_technology ;
acpi_integer design_voltage ;
acpi_integer design_capacity_warning ;
acpi_integer design_capacity_low ;
acpi_integer battery_capacity_granularity_1 ;
acpi_integer battery_capacity_granularity_2 ;
acpi_string model_number ;
acpi_string serial_number ;
acpi_string battery_type ;
acpi_string oem_info ;
2005-04-17 02:20:36 +04:00
} ;
struct acpi_battery_flags {
2005-08-05 08:44:28 +04:00
u8 present : 1 ; /* Bay occupied? */
u8 power_unit : 1 ; /* 0=watts, 1=apms */
u8 alarm : 1 ; /* _BTP present? */
u8 reserved : 5 ;
2005-04-17 02:20:36 +04:00
} ;
struct acpi_battery_trips {
2005-08-05 08:44:28 +04:00
unsigned long warning ;
unsigned long low ;
2005-04-17 02:20:36 +04:00
} ;
struct acpi_battery {
2006-05-20 00:54:39 +04:00
struct acpi_device * device ;
2005-04-17 02:20:36 +04:00
struct acpi_battery_flags flags ;
struct acpi_battery_trips trips ;
2005-08-05 08:44:28 +04:00
unsigned long alarm ;
2005-04-17 02:20:36 +04:00
struct acpi_battery_info * info ;
} ;
/* --------------------------------------------------------------------------
Battery Management
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
2005-08-05 08:44:28 +04:00
acpi_battery_get_info ( struct acpi_battery * battery ,
struct acpi_battery_info * * bif )
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 } ;
struct acpi_buffer format = { sizeof ( ACPI_BATTERY_FORMAT_BIF ) ,
ACPI_BATTERY_FORMAT_BIF
} ;
struct acpi_buffer data = { 0 , NULL } ;
union acpi_object * package = NULL ;
2005-04-17 02:20:36 +04:00
if ( ! battery | | ! bif )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
/* Evalute _BIF */
2006-05-20 00:54:41 +04:00
status = acpi_evaluate_object ( battery - > device - > handle , " _BIF " , NULL , & buffer ) ;
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
}
2005-08-05 08:44:28 +04:00
package = ( union acpi_object * ) buffer . pointer ;
2005-04-17 02:20:36 +04:00
/* Extract Package Data */
status = acpi_extract_package ( package , & format , & data ) ;
if ( status ! = AE_BUFFER_OVERFLOW ) {
2006-06-27 07:58:43 +04:00
ACPI_EXCEPTION ( ( AE_INFO , status , " Extracting _BIF " ) ) ;
2005-04-17 02:20:36 +04:00
result = - ENODEV ;
goto end ;
}
data . pointer = kmalloc ( data . length , GFP_KERNEL ) ;
if ( ! data . pointer ) {
result = - ENOMEM ;
goto end ;
}
memset ( data . pointer , 0 , data . length ) ;
status = acpi_extract_package ( package , & format , & data ) ;
if ( ACPI_FAILURE ( status ) ) {
2006-06-27 07:58:43 +04:00
ACPI_EXCEPTION ( ( AE_INFO , status , " Extracting _BIF " ) ) ;
2005-04-17 02:20:36 +04:00
kfree ( data . pointer ) ;
result = - ENODEV ;
goto end ;
}
2005-08-05 08:44:28 +04:00
end :
2006-06-30 11:19:10 +04:00
kfree ( buffer . pointer ) ;
2005-04-17 02:20:36 +04:00
if ( ! result )
2005-08-05 08:44:28 +04:00
( * bif ) = ( struct acpi_battery_info * ) data . pointer ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
static int
2005-08-05 08:44:28 +04:00
acpi_battery_get_status ( struct acpi_battery * battery ,
struct acpi_battery_status * * bst )
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 } ;
struct acpi_buffer format = { sizeof ( ACPI_BATTERY_FORMAT_BST ) ,
ACPI_BATTERY_FORMAT_BST
} ;
struct acpi_buffer data = { 0 , NULL } ;
union acpi_object * package = NULL ;
2005-04-17 02:20:36 +04:00
if ( ! battery | | ! bst )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
/* Evalute _BST */
2006-05-20 00:54:41 +04:00
status = acpi_evaluate_object ( battery - > device - > handle , " _BST " , NULL , & buffer ) ;
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
}
2005-08-05 08:44:28 +04:00
package = ( union acpi_object * ) buffer . pointer ;
2005-04-17 02:20:36 +04:00
/* Extract Package Data */
status = acpi_extract_package ( package , & format , & data ) ;
if ( status ! = AE_BUFFER_OVERFLOW ) {
2006-06-27 07:58:43 +04:00
ACPI_EXCEPTION ( ( AE_INFO , status , " Extracting _BST " ) ) ;
2005-04-17 02:20:36 +04:00
result = - ENODEV ;
goto end ;
}
data . pointer = kmalloc ( data . length , GFP_KERNEL ) ;
if ( ! data . pointer ) {
result = - ENOMEM ;
goto end ;
}
memset ( data . pointer , 0 , data . length ) ;
status = acpi_extract_package ( package , & format , & data ) ;
if ( ACPI_FAILURE ( status ) ) {
2006-06-27 07:58:43 +04:00
ACPI_EXCEPTION ( ( AE_INFO , status , " Extracting _BST " ) ) ;
2005-04-17 02:20:36 +04:00
kfree ( data . pointer ) ;
result = - ENODEV ;
goto end ;
}
2005-08-05 08:44:28 +04:00
end :
2006-06-30 11:19:10 +04:00
kfree ( buffer . pointer ) ;
2005-04-17 02:20:36 +04:00
if ( ! result )
2005-08-05 08:44:28 +04:00
( * bst ) = ( struct acpi_battery_status * ) data . pointer ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
static int
2005-08-05 08:44:28 +04:00
acpi_battery_set_alarm ( struct acpi_battery * battery , unsigned long alarm )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = 0 ;
union acpi_object arg0 = { ACPI_TYPE_INTEGER } ;
struct acpi_object_list arg_list = { 1 , & arg0 } ;
2005-04-17 02:20:36 +04:00
if ( ! battery )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( ! battery - > flags . alarm )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
arg0 . integer . value = alarm ;
2006-05-20 00:54:41 +04:00
status = acpi_evaluate_object ( battery - > device - > handle , " _BTP " , & arg_list , NULL ) ;
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
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Alarm set to %d \n " , ( u32 ) alarm ) ) ;
battery - > alarm = alarm ;
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 int acpi_battery_check ( 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 = AE_OK ;
acpi_handle handle = NULL ;
struct acpi_device * device = NULL ;
2005-04-17 02:20:36 +04:00
struct acpi_battery_info * bif = NULL ;
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
if ( ! battery )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2006-05-20 00:54:39 +04:00
device = battery - > device ;
2005-04-17 02:20:36 +04:00
result = acpi_bus_get_status ( device ) ;
if ( result )
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
/* Insertion? */
if ( ! battery - > flags . present & & device - > status . battery_present ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Battery inserted \n " ) ) ;
/* Evalute _BIF to get certain static information */
result = acpi_battery_get_info ( battery , & bif ) ;
if ( result )
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
battery - > flags . power_unit = bif - > power_unit ;
battery - > trips . warning = bif - > design_capacity_warning ;
battery - > trips . low = bif - > design_capacity_low ;
kfree ( bif ) ;
/* See if alarms are supported, and if so, set default */
2006-05-20 00:54:41 +04:00
status = acpi_get_handle ( battery - > device - > handle , " _BTP " , & handle ) ;
2005-04-17 02:20:36 +04:00
if ( ACPI_SUCCESS ( status ) ) {
battery - > flags . alarm = 1 ;
acpi_battery_set_alarm ( battery , battery - > trips . warning ) ;
}
}
/* Removal? */
else if ( battery - > flags . present & & ! device - > status . battery_present ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Battery removed \n " ) ) ;
}
battery - > flags . present = device - > status . battery_present ;
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
/* --------------------------------------------------------------------------
FS Interface ( / proc )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2005-08-05 08:44:28 +04:00
static struct proc_dir_entry * acpi_battery_dir ;
2005-04-17 02:20:36 +04:00
static int acpi_battery_read_info ( struct seq_file * seq , void * offset )
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
struct acpi_battery * battery = ( struct acpi_battery * ) seq - > private ;
2005-04-17 02:20:36 +04:00
struct acpi_battery_info * bif = NULL ;
2005-08-05 08:44:28 +04:00
char * units = " ? " ;
2005-04-17 02:20:36 +04:00
if ( ! battery )
goto end ;
if ( battery - > flags . present )
seq_printf ( seq , " present: yes \n " ) ;
else {
seq_printf ( seq , " present: no \n " ) ;
goto end ;
}
/* Battery Info (_BIF) */
result = acpi_battery_get_info ( battery , & bif ) ;
if ( result | | ! bif ) {
seq_printf ( seq , " ERROR: Unable to read battery information \n " ) ;
goto end ;
}
2005-08-05 08:44:28 +04:00
units =
bif - >
power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS ;
2005-04-17 02:20:36 +04:00
if ( bif - > design_capacity = = ACPI_BATTERY_VALUE_UNKNOWN )
seq_printf ( seq , " design capacity: unknown \n " ) ;
else
seq_printf ( seq , " design capacity: %d %sh \n " ,
2005-08-05 08:44:28 +04:00
( u32 ) bif - > design_capacity , units ) ;
2005-04-17 02:20:36 +04:00
if ( bif - > last_full_capacity = = ACPI_BATTERY_VALUE_UNKNOWN )
seq_printf ( seq , " last full capacity: unknown \n " ) ;
else
seq_printf ( seq , " last full capacity: %d %sh \n " ,
2005-08-05 08:44:28 +04:00
( u32 ) bif - > last_full_capacity , units ) ;
2005-04-17 02:20:36 +04:00
switch ( ( u32 ) bif - > battery_technology ) {
case 0 :
seq_printf ( seq , " battery technology: non-rechargeable \n " ) ;
break ;
case 1 :
seq_printf ( seq , " battery technology: rechargeable \n " ) ;
break ;
default :
seq_printf ( seq , " battery technology: unknown \n " ) ;
break ;
}
if ( bif - > design_voltage = = ACPI_BATTERY_VALUE_UNKNOWN )
seq_printf ( seq , " design voltage: unknown \n " ) ;
else
seq_printf ( seq , " design voltage: %d mV \n " ,
2005-08-05 08:44:28 +04:00
( u32 ) bif - > design_voltage ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " design capacity warning: %d %sh \n " ,
2005-08-05 08:44:28 +04:00
( u32 ) bif - > design_capacity_warning , units ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " design capacity low: %d %sh \n " ,
2005-08-05 08:44:28 +04:00
( u32 ) bif - > design_capacity_low , units ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " capacity granularity 1: %d %sh \n " ,
2005-08-05 08:44:28 +04:00
( u32 ) bif - > battery_capacity_granularity_1 , units ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " capacity granularity 2: %d %sh \n " ,
2005-08-05 08:44:28 +04:00
( u32 ) bif - > battery_capacity_granularity_2 , units ) ;
seq_printf ( seq , " model number: %s \n " , bif - > model_number ) ;
seq_printf ( seq , " serial number: %s \n " , bif - > serial_number ) ;
seq_printf ( seq , " battery type: %s \n " , bif - > battery_type ) ;
seq_printf ( seq , " OEM info: %s \n " , bif - > oem_info ) ;
end :
2005-04-17 02:20:36 +04:00
kfree ( bif ) ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int acpi_battery_info_open_fs ( struct inode * inode , struct file * file )
{
return single_open ( file , acpi_battery_read_info , PDE ( inode ) - > data ) ;
}
2005-08-05 08:44:28 +04:00
static int acpi_battery_read_state ( struct seq_file * seq , void * offset )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
struct acpi_battery * battery = ( struct acpi_battery * ) seq - > private ;
2005-04-17 02:20:36 +04:00
struct acpi_battery_status * bst = NULL ;
2005-08-05 08:44:28 +04:00
char * units = " ? " ;
2005-04-17 02:20:36 +04:00
if ( ! battery )
goto end ;
if ( battery - > flags . present )
seq_printf ( seq , " present: yes \n " ) ;
else {
seq_printf ( seq , " present: no \n " ) ;
goto end ;
}
/* Battery Units */
2005-08-05 08:44:28 +04:00
units =
battery - > flags .
power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS ;
2005-04-17 02:20:36 +04:00
/* Battery Status (_BST) */
result = acpi_battery_get_status ( battery , & bst ) ;
if ( result | | ! bst ) {
seq_printf ( seq , " ERROR: Unable to read battery status \n " ) ;
goto end ;
}
if ( ! ( bst - > state & 0x04 ) )
seq_printf ( seq , " capacity state: ok \n " ) ;
else
seq_printf ( seq , " capacity state: critical \n " ) ;
2005-08-05 08:44:28 +04:00
if ( ( bst - > state & 0x01 ) & & ( bst - > state & 0x02 ) ) {
seq_printf ( seq ,
" charging state: charging/discharging \n " ) ;
} else if ( bst - > state & 0x01 )
2005-04-17 02:20:36 +04:00
seq_printf ( seq , " charging state: discharging \n " ) ;
else if ( bst - > state & 0x02 )
seq_printf ( seq , " charging state: charging \n " ) ;
else {
seq_printf ( seq , " charging state: charged \n " ) ;
}
if ( bst - > present_rate = = ACPI_BATTERY_VALUE_UNKNOWN )
seq_printf ( seq , " present rate: unknown \n " ) ;
else
seq_printf ( seq , " present rate: %d %s \n " ,
2005-08-05 08:44:28 +04:00
( u32 ) bst - > present_rate , units ) ;
2005-04-17 02:20:36 +04:00
if ( bst - > remaining_capacity = = ACPI_BATTERY_VALUE_UNKNOWN )
seq_printf ( seq , " remaining capacity: unknown \n " ) ;
else
seq_printf ( seq , " remaining capacity: %d %sh \n " ,
2005-08-05 08:44:28 +04:00
( u32 ) bst - > remaining_capacity , units ) ;
2005-04-17 02:20:36 +04:00
if ( bst - > present_voltage = = ACPI_BATTERY_VALUE_UNKNOWN )
seq_printf ( seq , " present voltage: unknown \n " ) ;
else
seq_printf ( seq , " present voltage: %d mV \n " ,
2005-08-05 08:44:28 +04:00
( u32 ) bst - > present_voltage ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
end :
2005-04-17 02:20:36 +04:00
kfree ( bst ) ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int acpi_battery_state_open_fs ( struct inode * inode , struct file * file )
{
return single_open ( file , acpi_battery_read_state , PDE ( inode ) - > data ) ;
}
2005-08-05 08:44:28 +04:00
static int acpi_battery_read_alarm ( struct seq_file * seq , void * offset )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_battery * battery = ( struct acpi_battery * ) seq - > private ;
char * units = " ? " ;
2005-04-17 02:20:36 +04:00
if ( ! battery )
goto end ;
if ( ! battery - > flags . present ) {
seq_printf ( seq , " present: no \n " ) ;
goto end ;
}
/* Battery Units */
2005-08-05 08:44:28 +04:00
units =
battery - > flags .
power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS ;
2005-04-17 02:20:36 +04:00
/* Battery Alarm */
seq_printf ( seq , " alarm: " ) ;
if ( ! battery - > alarm )
seq_printf ( seq , " unsupported \n " ) ;
else
seq_printf ( seq , " %d %sh \n " , ( u32 ) battery - > alarm , units ) ;
2005-08-05 08:44:28 +04:00
end :
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static ssize_t
2005-08-05 08:44:28 +04:00
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 ' } ;
struct seq_file * m = ( struct seq_file * ) file - > private_data ;
struct acpi_battery * battery = ( struct acpi_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 ;
2005-04-17 02:20:36 +04:00
if ( ! battery - > flags . present )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
if ( copy_from_user ( alarm_string , buffer , count ) )
2006-06-27 08:41:40 +04:00
return - EFAULT ;
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
alarm_string [ count ] = ' \0 ' ;
2005-08-05 08:44:28 +04:00
result = acpi_battery_set_alarm ( battery ,
simple_strtoul ( alarm_string , NULL , 0 ) ) ;
2005-04-17 02:20:36 +04:00
if ( result )
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return count ;
2005-04-17 02:20:36 +04:00
}
static int acpi_battery_alarm_open_fs ( struct inode * inode , struct file * file )
{
return single_open ( file , acpi_battery_read_alarm , PDE ( inode ) - > data ) ;
}
2006-07-04 21:06:00 +04:00
static const struct file_operations acpi_battery_info_ops = {
2005-08-05 08:44:28 +04:00
. open = acpi_battery_info_open_fs ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
} ;
2006-07-04 21:06:00 +04:00
static const struct file_operations acpi_battery_state_ops = {
2005-08-05 08:44:28 +04:00
. open = acpi_battery_state_open_fs ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
} ;
2006-07-04 21:06:00 +04:00
static const struct file_operations acpi_battery_alarm_ops = {
2005-08-05 08:44:28 +04:00
. open = acpi_battery_alarm_open_fs ,
. read = seq_read ,
. write = acpi_battery_write_alarm ,
. llseek = seq_lseek ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
} ;
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 ;
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 ;
}
/* 'info' [R] */
entry = create_proc_entry ( ACPI_BATTERY_FILE_INFO ,
2005-08-05 08:44:28 +04:00
S_IRUGO , acpi_device_dir ( device ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! entry )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
else {
2005-08-05 08:44:28 +04:00
entry - > proc_fops = & acpi_battery_info_ops ;
2005-04-17 02:20:36 +04:00
entry - > data = acpi_driver_data ( device ) ;
entry - > owner = THIS_MODULE ;
}
/* 'status' [R] */
entry = create_proc_entry ( ACPI_BATTERY_FILE_STATUS ,
2005-08-05 08:44:28 +04:00
S_IRUGO , acpi_device_dir ( device ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! entry )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
else {
entry - > proc_fops = & acpi_battery_state_ops ;
entry - > data = acpi_driver_data ( device ) ;
entry - > owner = THIS_MODULE ;
}
/* 'alarm' [R/W] */
entry = create_proc_entry ( ACPI_BATTERY_FILE_ALARM ,
2005-08-05 08:44:28 +04:00
S_IFREG | S_IRUGO | S_IWUSR ,
acpi_device_dir ( device ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! entry )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
else {
entry - > proc_fops = & acpi_battery_alarm_ops ;
entry - > data = acpi_driver_data ( device ) ;
entry - > owner = THIS_MODULE ;
}
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 int acpi_battery_remove_fs ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
if ( acpi_device_dir ( device ) ) {
remove_proc_entry ( ACPI_BATTERY_FILE_ALARM ,
acpi_device_dir ( device ) ) ;
remove_proc_entry ( ACPI_BATTERY_FILE_STATUS ,
acpi_device_dir ( device ) ) ;
remove_proc_entry ( ACPI_BATTERY_FILE_INFO ,
acpi_device_dir ( device ) ) ;
remove_proc_entry ( acpi_device_bid ( device ) , acpi_battery_dir ) ;
acpi_device_dir ( device ) = NULL ;
}
2006-06-27 08:41:40 +04:00
return 0 ;
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
{
2005-08-05 08:44:28 +04:00
struct acpi_battery * battery = ( struct acpi_battery * ) data ;
struct acpi_device * device = NULL ;
2005-04-17 02:20:36 +04:00
if ( ! battery )
2006-06-27 08:41:40 +04:00
return ;
2005-04-17 02:20:36 +04:00
2006-05-20 00:54:39 +04:00
device = battery - > device ;
2005-04-17 02:20:36 +04:00
switch ( event ) {
case ACPI_BATTERY_NOTIFY_STATUS :
case ACPI_BATTERY_NOTIFY_INFO :
2006-06-27 12:49:00 +04:00
case ACPI_NOTIFY_BUS_CHECK :
case ACPI_NOTIFY_DEVICE_CHECK :
2005-04-17 02:20:36 +04:00
acpi_battery_check ( battery ) ;
acpi_bus_generate_event ( device , event , battery - > flags . present ) ;
break ;
default :
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
2005-08-05 08:44:28 +04:00
" Unsupported event [0x%x] \n " , event ) ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2006-06-27 08:41:40 +04:00
return ;
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
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
if ( ! device )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
battery = kmalloc ( sizeof ( struct acpi_battery ) , GFP_KERNEL ) ;
if ( ! battery )
2006-06-27 08:41:40 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
memset ( battery , 0 , sizeof ( struct acpi_battery ) ) ;
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 ;
result = acpi_battery_check ( battery ) ;
if ( result )
goto end ;
result = acpi_battery_add_fs ( device ) ;
if ( result )
goto end ;
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 ) ) {
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 ) {
acpi_battery_remove_fs ( device ) ;
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 ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
battery = ( struct acpi_battery * ) acpi_driver_data ( device ) ;
2005-04-17 02:20:36 +04:00
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 ) ;
2005-04-17 02:20:36 +04:00
acpi_battery_remove_fs ( device ) ;
kfree ( battery ) ;
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 int __init acpi_battery_init ( void )
2005-04-17 02:20:36 +04:00
{
2006-07-01 19:36:54 +04:00
int result ;
2005-04-17 02:20:36 +04:00
2006-08-15 09:37:22 +04:00
if ( acpi_disabled )
return - ENODEV ;
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 ;
2005-04-17 02:20:36 +04:00
result = acpi_bus_register_driver ( & acpi_battery_driver ) ;
if ( result < 0 ) {
2006-07-01 19:36:54 +04:00
acpi_unlock_battery_dir ( acpi_battery_dir ) ;
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 ) ;
2006-07-01 19:36:54 +04:00
acpi_unlock_battery_dir ( acpi_battery_dir ) ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return ;
2005-04-17 02:20:36 +04:00
}
module_init ( acpi_battery_init ) ;
module_exit ( acpi_battery_exit ) ;