2005-04-17 02:20:36 +04:00
/*
2007-03-07 22:28:00 +03:00
* ec . c - ACPI Embedded Controller Driver ( v2 .0 )
2005-04-17 02:20:36 +04:00
*
2007-03-07 22:28:00 +03:00
* Copyright ( C ) 2006 , 2007 Alexey Starikovskiy < alexey . y . starikovskiy @ intel . com >
* Copyright ( C ) 2006 Denis Sadykov < denis . m . sadykov @ intel . com >
2005-04-17 02:20:36 +04:00
* Copyright ( C ) 2004 Luming Yu < luming . yu @ intel . com >
* 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/delay.h>
# include <linux/proc_fs.h>
# include <linux/seq_file.h>
2005-03-19 09:10:05 +03:00
# include <linux/interrupt.h>
2005-04-17 02:20:36 +04:00
# include <asm/io.h>
# include <acpi/acpi_bus.h>
# include <acpi/acpi_drivers.h>
# include <acpi/actypes.h>
# define _COMPONENT ACPI_EC_COMPONENT
2007-02-13 06:42:12 +03:00
ACPI_MODULE_NAME ( " ec " ) ;
2005-04-17 02:20:36 +04:00
# define ACPI_EC_COMPONENT 0x00100000
# define ACPI_EC_CLASS "embedded_controller"
# define ACPI_EC_HID "PNP0C09"
# define ACPI_EC_DEVICE_NAME "Embedded Controller"
# define ACPI_EC_FILE_INFO "info"
2006-12-07 18:42:16 +03:00
# undef PREFIX
# define PREFIX "ACPI: EC: "
2006-09-26 19:50:33 +04:00
/* EC status register */
2005-04-17 02:20:36 +04:00
# define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */
# define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */
2005-03-19 09:10:05 +03:00
# define ACPI_EC_FLAG_BURST 0x10 /* burst mode */
2005-04-17 02:20:36 +04:00
# define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */
2006-09-26 19:50:33 +04:00
/* EC commands */
2006-12-07 18:42:17 +03:00
enum ec_command {
2006-12-07 18:42:17 +03:00
ACPI_EC_COMMAND_READ = 0x80 ,
ACPI_EC_COMMAND_WRITE = 0x81 ,
ACPI_EC_BURST_ENABLE = 0x82 ,
ACPI_EC_BURST_DISABLE = 0x83 ,
ACPI_EC_COMMAND_QUERY = 0x84 ,
2006-12-07 18:42:17 +03:00
} ;
2006-09-26 19:50:33 +04:00
/* EC events */
2006-12-07 18:42:17 +03:00
enum ec_event {
2006-09-26 19:50:33 +04:00
ACPI_EC_EVENT_OBF_1 = 1 , /* Output buffer full */
2006-12-07 18:42:17 +03:00
ACPI_EC_EVENT_IBF_0 , /* Input buffer empty */
2006-09-26 19:50:33 +04:00
} ;
2006-12-07 18:42:16 +03:00
# define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */
2006-09-26 19:50:33 +04:00
# define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
2006-12-07 18:42:17 +03:00
static enum ec_mode {
2006-12-07 18:42:17 +03:00
EC_INTR = 1 , /* Output buffer full */
EC_POLL , /* Input buffer empty */
2006-12-07 18:42:17 +03:00
} acpi_ec_mode = EC_INTR ;
2006-09-26 19:50:33 +04:00
2005-08-12 01:32:05 +04:00
static int acpi_ec_remove ( struct acpi_device * device , int type ) ;
static int acpi_ec_start ( struct acpi_device * device ) ;
static int acpi_ec_stop ( struct acpi_device * device , int type ) ;
2006-09-26 19:50:33 +04:00
static int acpi_ec_add ( struct acpi_device * device ) ;
2005-04-17 02:20:36 +04:00
static struct acpi_driver acpi_ec_driver = {
2007-02-13 07:33:40 +03:00
. name = " ec " ,
2005-08-12 01:32:05 +04:00
. class = ACPI_EC_CLASS ,
. ids = ACPI_EC_HID ,
. ops = {
2006-09-26 19:50:33 +04:00
. add = acpi_ec_add ,
2005-08-12 01:32:05 +04:00
. remove = acpi_ec_remove ,
. start = acpi_ec_start ,
. stop = acpi_ec_stop ,
} ,
2005-04-17 02:20:36 +04:00
} ;
2006-09-26 19:50:33 +04:00
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
2007-03-07 22:28:00 +03:00
/* External interfaces use first EC only, so remember */
2006-12-19 23:56:12 +03:00
static struct acpi_ec {
2006-09-26 19:50:33 +04:00
acpi_handle handle ;
2006-12-07 18:42:16 +03:00
unsigned long gpe ;
2006-09-26 19:50:33 +04:00
unsigned long command_addr ;
unsigned long data_addr ;
2006-09-26 19:50:33 +04:00
unsigned long global_lock ;
2006-12-07 18:42:16 +03:00
struct mutex lock ;
2006-12-07 18:42:16 +03:00
atomic_t query_pending ;
2007-03-08 02:29:35 +03:00
atomic_t event_count ;
2006-09-26 19:50:33 +04:00
wait_queue_head_t wait ;
2007-03-07 22:28:00 +03:00
} * boot_ec , * first_ec ;
2006-09-26 19:50:33 +04:00
2005-04-17 02:20:36 +04:00
/* --------------------------------------------------------------------------
Transaction Management
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2006-09-26 19:50:33 +04:00
static inline u8 acpi_ec_read_status ( struct acpi_ec * ec )
2005-04-17 02:20:36 +04:00
{
2006-09-26 19:50:33 +04:00
return inb ( ec - > command_addr ) ;
2005-03-19 09:10:05 +03:00
}
2006-09-26 19:50:33 +04:00
static inline u8 acpi_ec_read_data ( struct acpi_ec * ec )
2006-09-26 19:50:33 +04:00
{
2006-09-26 19:50:33 +04:00
return inb ( ec - > data_addr ) ;
2006-09-26 19:50:33 +04:00
}
2006-09-26 19:50:33 +04:00
static inline void acpi_ec_write_cmd ( struct acpi_ec * ec , u8 command )
2005-07-23 12:08:00 +04:00
{
2006-09-26 19:50:33 +04:00
outb ( command , ec - > command_addr ) ;
2005-07-23 12:08:00 +04:00
}
2006-09-26 19:50:33 +04:00
static inline void acpi_ec_write_data ( struct acpi_ec * ec , u8 data )
2005-07-23 12:08:00 +04:00
{
2006-09-26 19:50:33 +04:00
outb ( data , ec - > data_addr ) ;
2006-09-26 19:50:33 +04:00
}
2005-07-23 12:08:00 +04:00
2007-03-08 02:29:35 +03:00
static inline int acpi_ec_check_status ( struct acpi_ec * ec , enum ec_event event ,
unsigned old_count )
2006-09-26 19:50:33 +04:00
{
2006-12-07 18:42:16 +03:00
u8 status = acpi_ec_read_status ( ec ) ;
2007-03-08 02:29:35 +03:00
if ( old_count = = atomic_read ( & ec - > event_count ) )
return 0 ;
2006-12-07 18:42:17 +03:00
if ( event = = ACPI_EC_EVENT_OBF_1 ) {
2006-09-26 19:50:33 +04:00
if ( status & ACPI_EC_FLAG_OBF )
return 1 ;
2006-12-07 18:42:17 +03:00
} else if ( event = = ACPI_EC_EVENT_IBF_0 ) {
2006-09-26 19:50:33 +04:00
if ( ! ( status & ACPI_EC_FLAG_IBF ) )
return 1 ;
2005-07-23 12:08:00 +04:00
}
2006-09-26 19:50:33 +04:00
return 0 ;
2005-07-23 12:08:00 +04:00
}
2005-03-19 09:10:05 +03:00
2007-03-08 02:29:35 +03:00
static int acpi_ec_wait ( struct acpi_ec * ec , enum ec_event event , unsigned count )
2006-09-26 19:50:33 +04:00
{
2006-12-07 18:42:16 +03:00
if ( acpi_ec_mode = = EC_POLL ) {
2006-12-07 18:42:17 +03:00
unsigned long delay = jiffies + msecs_to_jiffies ( ACPI_EC_DELAY ) ;
while ( time_before ( jiffies , delay ) ) {
2007-03-08 02:29:35 +03:00
if ( acpi_ec_check_status ( ec , event , 0 ) )
2006-09-26 19:50:33 +04:00
return 0 ;
}
2006-12-07 18:42:16 +03:00
} else {
if ( wait_event_timeout ( ec - > wait ,
2007-03-08 02:29:35 +03:00
acpi_ec_check_status ( ec , event , count ) ,
2006-12-07 18:42:16 +03:00
msecs_to_jiffies ( ACPI_EC_DELAY ) ) | |
2007-03-08 02:29:35 +03:00
acpi_ec_check_status ( ec , event , 0 ) ) {
2006-09-26 19:50:33 +04:00
return 0 ;
2006-12-07 18:42:16 +03:00
} else {
printk ( KERN_ERR PREFIX " acpi_ec_wait timeout, "
" status = %d, expect_event = %d \n " ,
2006-12-07 18:42:17 +03:00
acpi_ec_read_status ( ec ) , event ) ;
2006-09-26 19:50:33 +04:00
}
2006-12-07 18:42:16 +03:00
}
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return - ETIME ;
2005-04-17 02:20:36 +04:00
}
2006-09-26 19:50:33 +04:00
static int acpi_ec_transaction_unlocked ( struct acpi_ec * ec , u8 command ,
2006-12-07 18:42:17 +03:00
const u8 * wdata , unsigned wdata_len ,
u8 * rdata , unsigned rdata_len )
2005-07-23 12:08:00 +04:00
{
2006-12-07 18:42:16 +03:00
int result = 0 ;
2007-03-08 02:29:35 +03:00
unsigned count = atomic_read ( & ec - > event_count ) ;
2006-09-26 19:50:33 +04:00
acpi_ec_write_cmd ( ec , command ) ;
2005-07-23 12:08:00 +04:00
2006-12-07 18:42:17 +03:00
for ( ; wdata_len > 0 ; - - wdata_len ) {
2007-03-08 02:29:35 +03:00
result = acpi_ec_wait ( ec , ACPI_EC_EVENT_IBF_0 , count ) ;
2006-12-07 18:42:16 +03:00
if ( result ) {
2006-12-07 18:42:17 +03:00
printk ( KERN_ERR PREFIX
" write_cmd timeout, command = %d \n " , command ) ;
2006-12-07 18:42:16 +03:00
goto end ;
}
2007-03-08 02:29:35 +03:00
count = atomic_read ( & ec - > event_count ) ;
2006-09-26 19:50:33 +04:00
acpi_ec_write_data ( ec , * ( wdata + + ) ) ;
2006-09-26 19:50:33 +04:00
}
2005-07-23 12:08:00 +04:00
2006-12-07 18:42:16 +03:00
if ( ! rdata_len ) {
2007-03-08 02:29:35 +03:00
result = acpi_ec_wait ( ec , ACPI_EC_EVENT_IBF_0 , count ) ;
2006-12-07 18:42:16 +03:00
if ( result ) {
2006-12-07 18:42:17 +03:00
printk ( KERN_ERR PREFIX
" finish-write timeout, command = %d \n " , command ) ;
2006-12-07 18:42:16 +03:00
goto end ;
}
2006-12-07 18:42:16 +03:00
} else if ( command = = ACPI_EC_COMMAND_QUERY ) {
atomic_set ( & ec - > query_pending , 0 ) ;
2006-09-26 19:50:33 +04:00
}
2005-07-23 12:08:00 +04:00
2006-12-07 18:42:17 +03:00
for ( ; rdata_len > 0 ; - - rdata_len ) {
2007-03-08 02:29:35 +03:00
result = acpi_ec_wait ( ec , ACPI_EC_EVENT_OBF_1 , count ) ;
2006-12-07 18:42:16 +03:00
if ( result ) {
printk ( KERN_ERR PREFIX " read timeout, command = %d \n " ,
2006-12-07 18:42:17 +03:00
command ) ;
2006-12-07 18:42:16 +03:00
goto end ;
}
2007-03-08 02:29:35 +03:00
count = atomic_read ( & ec - > event_count ) ;
2006-09-26 19:50:33 +04:00
* ( rdata + + ) = acpi_ec_read_data ( ec ) ;
2006-09-26 19:50:33 +04:00
}
2006-12-07 18:42:16 +03:00
end :
return result ;
2005-07-23 12:08:00 +04:00
}
2006-09-26 19:50:33 +04:00
static int acpi_ec_transaction ( struct acpi_ec * ec , u8 command ,
2006-12-07 18:42:17 +03:00
const u8 * wdata , unsigned wdata_len ,
u8 * rdata , unsigned rdata_len )
2005-04-17 02:20:36 +04:00
{
2006-09-05 20:12:24 +04:00
int status ;
2005-08-12 01:32:05 +04:00
u32 glk ;
2005-04-17 02:20:36 +04:00
2006-09-05 20:12:24 +04:00
if ( ! ec | | ( wdata_len & & ! wdata ) | | ( rdata_len & & ! rdata ) )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2006-12-07 18:42:17 +03:00
if ( rdata )
memset ( rdata , 0 , rdata_len ) ;
2005-04-17 02:20:36 +04:00
2006-12-07 18:42:17 +03:00
mutex_lock ( & ec - > lock ) ;
2006-09-26 19:50:33 +04:00
if ( ec - > global_lock ) {
2005-04-17 02:20:36 +04:00
status = acpi_acquire_global_lock ( ACPI_EC_UDELAY_GLK , & glk ) ;
2007-02-15 23:16:18 +03:00
if ( ACPI_FAILURE ( status ) ) {
mutex_unlock ( & ec - > lock ) ;
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2007-02-15 23:16:18 +03:00
}
2005-04-17 02:20:36 +04:00
}
2005-03-19 09:10:05 +03:00
2006-12-07 18:42:16 +03:00
/* Make sure GPE is enabled before doing transaction */
2006-12-07 18:42:16 +03:00
acpi_enable_gpe ( NULL , ec - > gpe , ACPI_NOT_ISR ) ;
2006-12-07 18:42:16 +03:00
2007-03-08 02:29:35 +03:00
status = acpi_ec_wait ( ec , ACPI_EC_EVENT_IBF_0 , 0 ) ;
2005-08-10 09:40:00 +04:00
if ( status ) {
2006-12-07 18:42:17 +03:00
printk ( KERN_DEBUG PREFIX
" input buffer is not empty, aborting transaction \n " ) ;
2005-03-19 09:10:05 +03:00
goto end ;
2005-08-10 09:40:00 +04:00
}
2005-04-17 02:20:36 +04:00
2006-12-07 18:42:17 +03:00
status = acpi_ec_transaction_unlocked ( ec , command ,
wdata , wdata_len ,
rdata , rdata_len ) ;
2005-04-17 02:20:36 +04:00
2006-12-07 18:42:17 +03:00
end :
2005-04-17 02:20:36 +04:00
2006-09-26 19:50:33 +04:00
if ( ec - > global_lock )
2005-04-17 02:20:36 +04:00
acpi_release_global_lock ( glk ) ;
2006-12-07 18:42:17 +03:00
mutex_unlock ( & ec - > lock ) ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
2007-03-07 22:28:00 +03:00
/*
* Note : samsung nv5000 doesn ' t work with ec burst mode .
* http : //bugzilla.kernel.org/show_bug.cgi?id=4980
*/
int acpi_ec_burst_enable ( struct acpi_ec * ec )
{
u8 d ;
return acpi_ec_transaction ( ec , ACPI_EC_BURST_ENABLE , NULL , 0 , & d , 1 ) ;
}
int acpi_ec_burst_disable ( struct acpi_ec * ec )
{
return acpi_ec_transaction ( ec , ACPI_EC_BURST_DISABLE , NULL , 0 , NULL , 0 ) ;
}
2006-12-07 18:42:17 +03:00
static int acpi_ec_read ( struct acpi_ec * ec , u8 address , u8 * data )
2006-09-26 19:50:33 +04:00
{
int result ;
u8 d ;
result = acpi_ec_transaction ( ec , ACPI_EC_COMMAND_READ ,
& address , 1 , & d , 1 ) ;
* data = d ;
return result ;
}
2006-09-26 19:50:33 +04:00
2006-09-26 19:50:33 +04:00
static int acpi_ec_write ( struct acpi_ec * ec , u8 address , u8 data )
{
2006-12-07 18:42:17 +03:00
u8 wdata [ 2 ] = { address , data } ;
return acpi_ec_transaction ( ec , ACPI_EC_COMMAND_WRITE ,
2006-09-26 19:50:33 +04:00
wdata , 2 , NULL , 0 ) ;
}
2005-04-17 02:20:36 +04:00
/*
* Externally callable EC access functions . For now , assume 1 EC only
*/
2007-03-07 22:28:00 +03:00
int ec_burst_enable ( void )
{
if ( ! first_ec )
return - ENODEV ;
2007-03-07 22:28:00 +03:00
return acpi_ec_burst_enable ( first_ec ) ;
2007-03-07 22:28:00 +03:00
}
EXPORT_SYMBOL ( ec_burst_enable ) ;
int ec_burst_disable ( void )
{
if ( ! first_ec )
return - ENODEV ;
2007-03-07 22:28:00 +03:00
return acpi_ec_burst_disable ( first_ec ) ;
2007-03-07 22:28:00 +03:00
}
EXPORT_SYMBOL ( ec_burst_disable ) ;
2006-12-07 18:42:17 +03:00
int ec_read ( u8 addr , u8 * val )
2005-04-17 02:20:36 +04:00
{
int err ;
2006-09-26 19:50:33 +04:00
u8 temp_data ;
2005-04-17 02:20:36 +04:00
if ( ! first_ec )
return - ENODEV ;
2007-03-07 22:28:00 +03:00
err = acpi_ec_read ( first_ec , addr , & temp_data ) ;
2005-04-17 02:20:36 +04:00
if ( ! err ) {
* val = temp_data ;
return 0 ;
2005-08-12 01:32:05 +04:00
} else
2005-04-17 02:20:36 +04:00
return err ;
}
2005-08-12 01:32:05 +04:00
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( ec_read ) ;
2005-08-12 01:32:05 +04:00
int ec_write ( u8 addr , u8 val )
2005-04-17 02:20:36 +04:00
{
int err ;
if ( ! first_ec )
return - ENODEV ;
2007-03-07 22:28:00 +03:00
err = acpi_ec_write ( first_ec , addr , val ) ;
2005-04-17 02:20:36 +04:00
return err ;
}
2005-08-12 01:32:05 +04:00
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( ec_write ) ;
2006-10-27 09:47:34 +04:00
int ec_transaction ( u8 command ,
2007-03-08 02:29:35 +03:00
const u8 * wdata , unsigned wdata_len ,
u8 * rdata , unsigned rdata_len )
2005-07-23 12:08:00 +04:00
{
2006-09-05 20:12:24 +04:00
if ( ! first_ec )
return - ENODEV ;
2005-07-23 12:08:00 +04:00
2007-03-07 22:28:00 +03:00
return acpi_ec_transaction ( first_ec , command , wdata ,
2006-09-26 19:50:33 +04:00
wdata_len , rdata , rdata_len ) ;
2005-07-23 12:08:00 +04:00
}
2005-04-17 02:20:36 +04:00
2006-10-04 06:49:00 +04:00
EXPORT_SYMBOL ( ec_transaction ) ;
2006-12-07 18:42:17 +03:00
static int acpi_ec_query ( struct acpi_ec * ec , u8 * data )
2006-09-26 19:50:33 +04:00
{
int result ;
2006-12-07 18:42:17 +03:00
u8 d ;
2005-04-17 02:20:36 +04:00
2006-12-07 18:42:17 +03:00
if ( ! ec | | ! data )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2006-12-07 18:42:17 +03:00
/*
* Query the EC to find out which _Qxx method we need to evaluate .
* Note that successful completion of the query causes the ACPI_EC_SCI
* bit to be cleared ( and thus clearing the interrupt source ) .
*/
2005-08-10 09:40:00 +04:00
2006-12-07 18:42:17 +03:00
result = acpi_ec_transaction ( ec , ACPI_EC_COMMAND_QUERY , NULL , 0 , & d , 1 ) ;
if ( result )
return result ;
2005-04-17 02:20:36 +04:00
2006-12-07 18:42:17 +03:00
if ( ! d )
return - ENODATA ;
2005-04-17 02:20:36 +04:00
2006-12-07 18:42:17 +03:00
* data = d ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
/* --------------------------------------------------------------------------
Event Management
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2005-08-12 01:32:05 +04:00
static void acpi_ec_gpe_query ( void * ec_cxt )
2005-07-23 12:08:00 +04:00
{
2007-03-07 22:28:00 +03:00
struct acpi_ec * ec = ec_cxt ;
2006-09-26 19:50:33 +04:00
u8 value = 0 ;
2006-12-07 18:42:16 +03:00
char object_name [ 8 ] ;
2005-07-23 12:08:00 +04:00
2006-12-07 18:42:16 +03:00
if ( ! ec | | acpi_ec_query ( ec , & value ) )
2006-12-07 18:42:16 +03:00
return ;
2005-07-23 12:08:00 +04:00
2006-09-26 19:50:33 +04:00
snprintf ( object_name , 8 , " _Q%2.2X " , value ) ;
2005-07-23 12:08:00 +04:00
2006-12-25 00:19:02 +03:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Evaluating %s " , object_name ) ) ;
2005-07-23 12:08:00 +04:00
2006-09-26 19:50:33 +04:00
acpi_evaluate_object ( ec - > handle , object_name , NULL , NULL ) ;
2005-07-23 12:08:00 +04:00
}
2005-04-17 02:20:36 +04:00
2005-08-12 01:32:05 +04:00
static u32 acpi_ec_gpe_handler ( void * data )
2005-04-17 02:20:36 +04:00
{
2005-08-12 01:32:05 +04:00
acpi_status status = AE_OK ;
2006-09-26 19:50:33 +04:00
u8 value ;
2007-03-07 22:28:00 +03:00
struct acpi_ec * ec = data ;
2007-03-08 02:29:35 +03:00
atomic_inc ( & ec - > event_count ) ;
2007-03-07 22:28:00 +03:00
2006-09-26 19:50:33 +04:00
if ( acpi_ec_mode = = EC_INTR ) {
2006-12-07 18:42:16 +03:00
wake_up ( & ec - > wait ) ;
2005-03-19 09:10:05 +03:00
}
2006-12-07 18:42:16 +03:00
value = acpi_ec_read_status ( ec ) ;
2006-12-07 18:42:16 +03:00
if ( ( value & ACPI_EC_FLAG_SCI ) & & ! atomic_read ( & ec - > query_pending ) ) {
atomic_set ( & ec - > query_pending , 1 ) ;
2006-12-07 18:42:17 +03:00
status =
acpi_os_execute ( OSL_EC_BURST_HANDLER , acpi_ec_gpe_query ,
ec ) ;
2005-08-12 01:32:05 +04:00
}
2006-12-07 18:42:16 +03:00
2005-03-19 09:10:05 +03:00
return status = = AE_OK ?
2005-08-12 01:32:05 +04:00
ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED ;
2005-04-17 02:20:36 +04:00
}
/* --------------------------------------------------------------------------
Address Space Management
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static acpi_status
2005-08-12 01:32:05 +04:00
acpi_ec_space_setup ( acpi_handle region_handle ,
u32 function , void * handler_context , void * * return_context )
2005-04-17 02:20:36 +04:00
{
/*
* The EC object is in the handler context and is needed
* when calling the acpi_ec_space_handler .
*/
2005-08-12 01:32:05 +04:00
* return_context = ( function ! = ACPI_REGION_DEACTIVATE ) ?
handler_context : NULL ;
2005-04-17 02:20:36 +04:00
return AE_OK ;
}
static acpi_status
2005-08-12 01:32:05 +04:00
acpi_ec_space_handler ( u32 function ,
acpi_physical_address address ,
u32 bit_width ,
acpi_integer * value ,
void * handler_context , void * region_context )
2005-04-17 02:20:36 +04:00
{
2005-08-12 01:32:05 +04:00
int result = 0 ;
2007-03-07 22:28:00 +03:00
struct acpi_ec * ec = handler_context ;
2005-08-12 01:32:05 +04:00
u64 temp = * value ;
acpi_integer f_v = 0 ;
int i = 0 ;
2005-04-17 02:20:36 +04:00
if ( ( address > 0xFF ) | | ! value | | ! handler_context )
2006-06-27 08:41:40 +04:00
return AE_BAD_PARAMETER ;
2005-04-17 02:20:36 +04:00
2005-03-19 09:54:47 +03:00
if ( bit_width ! = 8 & & acpi_strict ) {
2006-06-27 08:41:40 +04:00
return AE_BAD_PARAMETER ;
2005-04-17 02:20:36 +04:00
}
2005-08-12 01:32:05 +04:00
next_byte :
2005-04-17 02:20:36 +04:00
switch ( function ) {
case ACPI_READ :
2005-03-19 09:54:47 +03:00
temp = 0 ;
2006-12-07 18:42:17 +03:00
result = acpi_ec_read ( ec , ( u8 ) address , ( u8 * ) & temp ) ;
2005-04-17 02:20:36 +04:00
break ;
case ACPI_WRITE :
2005-03-19 09:54:47 +03:00
result = acpi_ec_write ( ec , ( u8 ) address , ( u8 ) temp ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
result = - EINVAL ;
goto out ;
break ;
}
bit_width - = 8 ;
2005-03-19 09:54:47 +03:00
if ( bit_width ) {
if ( function = = ACPI_READ )
f_v | = temp < < 8 * i ;
if ( function = = ACPI_WRITE )
temp > > = 8 ;
2005-04-17 02:20:36 +04:00
i + + ;
2005-03-31 07:12:13 +04:00
address + + ;
2005-04-17 02:20:36 +04:00
goto next_byte ;
}
2005-03-19 09:54:47 +03:00
if ( function = = ACPI_READ ) {
f_v | = temp < < 8 * i ;
2005-04-17 02:20:36 +04:00
* value = f_v ;
}
2005-08-12 01:32:05 +04:00
out :
2005-04-17 02:20:36 +04:00
switch ( result ) {
case - EINVAL :
2006-06-27 08:41:40 +04:00
return AE_BAD_PARAMETER ;
2005-04-17 02:20:36 +04:00
break ;
case - ENODEV :
2006-06-27 08:41:40 +04:00
return AE_NOT_FOUND ;
2005-04-17 02:20:36 +04:00
break ;
case - ETIME :
2006-06-27 08:41:40 +04:00
return AE_TIME ;
2005-04-17 02:20:36 +04:00
break ;
default :
2006-06-27 08:41:40 +04:00
return AE_OK ;
2005-04-17 02:20:36 +04:00
}
}
/* --------------------------------------------------------------------------
FS Interface ( / proc )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2005-08-12 01:32:05 +04:00
static struct proc_dir_entry * acpi_ec_dir ;
2005-04-17 02:20:36 +04:00
2005-08-12 01:32:05 +04:00
static int acpi_ec_read_info ( struct seq_file * seq , void * offset )
2005-04-17 02:20:36 +04:00
{
2007-03-07 22:28:00 +03:00
struct acpi_ec * ec = seq - > private ;
2005-04-17 02:20:36 +04:00
if ( ! ec )
goto end ;
2007-03-07 22:28:00 +03:00
seq_printf ( seq , " gpe: \t \t \t 0x%02x \n " , ( u32 ) ec - > gpe ) ;
seq_printf ( seq , " ports: \t \t \t 0x%02x, 0x%02x \n " ,
( unsigned ) ec - > command_addr , ( unsigned ) ec - > data_addr ) ;
seq_printf ( seq , " use global lock: \t %s \n " ,
2006-09-26 19:50:33 +04:00
ec - > global_lock ? " yes " : " no " ) ;
2005-08-12 01:32:05 +04:00
end :
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int acpi_ec_info_open_fs ( struct inode * inode , struct file * file )
{
return single_open ( file , acpi_ec_read_info , PDE ( inode ) - > data ) ;
}
2006-09-26 19:50:33 +04:00
static struct file_operations acpi_ec_info_ops = {
2005-08-12 01:32:05 +04:00
. open = acpi_ec_info_open_fs ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
} ;
2005-08-12 01:32:05 +04:00
static int acpi_ec_add_fs ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2005-08-12 01:32:05 +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-12 01:32:05 +04:00
acpi_ec_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
}
entry = create_proc_entry ( ACPI_EC_FILE_INFO , S_IRUGO ,
2005-08-12 01:32:05 +04:00
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_ec_info_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-12 01:32:05 +04:00
static int acpi_ec_remove_fs ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
if ( acpi_device_dir ( device ) ) {
remove_proc_entry ( ACPI_EC_FILE_INFO , acpi_device_dir ( device ) ) ;
remove_proc_entry ( acpi_device_bid ( device ) , acpi_ec_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
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-03-07 22:28:00 +03:00
static acpi_status
ec_parse_io_ports ( struct acpi_resource * resource , void * context ) ;
static acpi_status
ec_parse_device ( acpi_handle handle , u32 Level , void * context , void * * retval ) ;
static struct acpi_ec * make_acpi_ec ( void )
{
struct acpi_ec * ec = kzalloc ( sizeof ( struct acpi_ec ) , GFP_KERNEL ) ;
if ( ! ec )
return NULL ;
2007-03-07 22:28:00 +03:00
atomic_set ( & ec - > query_pending , 1 ) ;
2007-03-07 22:28:00 +03:00
atomic_set ( & ec - > event_count , 1 ) ;
mutex_init ( & ec - > lock ) ;
init_waitqueue_head ( & ec - > wait ) ;
return ec ;
}
2005-04-17 02:20:36 +04:00
2006-09-26 19:50:33 +04:00
static int acpi_ec_add ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2005-08-12 01:32:05 +04:00
acpi_status status = AE_OK ;
2006-09-26 19:50:33 +04:00
struct acpi_ec * ec = NULL ;
2005-07-23 12:08:00 +04:00
if ( ! device )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-07-23 12:08:00 +04:00
2007-03-07 22:28:00 +03:00
strcpy ( acpi_device_name ( device ) , ACPI_EC_DEVICE_NAME ) ;
strcpy ( acpi_device_class ( device ) , ACPI_EC_CLASS ) ;
ec = make_acpi_ec ( ) ;
2005-07-23 12:08:00 +04:00
if ( ! ec )
2006-06-27 08:41:40 +04:00
return - ENOMEM ;
2006-09-26 19:50:33 +04:00
2007-03-07 22:28:00 +03:00
status = ec_parse_device ( device - > handle , 0 , ec , NULL ) ;
if ( status ! = AE_CTRL_TERMINATE ) {
kfree ( ec ) ;
return - EINVAL ;
2005-07-23 12:08:00 +04:00
}
2005-04-17 02:20:36 +04:00
2007-03-07 22:28:00 +03:00
/* Check if we found the boot EC */
2007-03-07 22:28:00 +03:00
if ( boot_ec ) {
if ( boot_ec - > gpe = = ec - > gpe ) {
2007-03-07 22:28:00 +03:00
/* We might have incorrect info for GL at boot time */
2007-03-07 22:28:00 +03:00
mutex_lock ( & boot_ec - > lock ) ;
boot_ec - > global_lock = ec - > global_lock ;
mutex_unlock ( & boot_ec - > lock ) ;
2007-03-07 22:28:00 +03:00
kfree ( ec ) ;
2007-03-07 22:28:00 +03:00
ec = boot_ec ;
2007-03-07 22:28:00 +03:00
}
2007-03-07 22:28:00 +03:00
} else
first_ec = ec ;
2007-03-07 22:28:00 +03:00
ec - > handle = device - > handle ;
acpi_driver_data ( device ) = ec ;
2005-04-17 02:20:36 +04:00
2007-03-07 22:28:00 +03:00
acpi_ec_add_fs ( device ) ;
2005-04-17 02:20:36 +04:00
2006-09-26 19:50:33 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " %s [%s] (gpe %d) interrupt mode. " ,
2006-12-07 18:42:17 +03:00
acpi_device_name ( device ) , acpi_device_bid ( device ) ,
( u32 ) ec - > gpe ) ) ;
2005-04-17 02:20:36 +04:00
2007-03-07 22:28:00 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-08-12 01:32:05 +04:00
static int acpi_ec_remove ( struct acpi_device * device , int type )
2005-04-17 02:20:36 +04:00
{
2007-03-07 22:28:00 +03:00
struct acpi_ec * ec ;
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
ec = acpi_driver_data ( device ) ;
acpi_ec_remove_fs ( device ) ;
2007-03-07 22:28:00 +03:00
acpi_driver_data ( device ) = NULL ;
2007-03-07 22:28:00 +03:00
if ( ec = = first_ec )
2007-03-07 22:28:00 +03:00
first_ec = NULL ;
/* Don't touch boot EC */
2007-03-07 22:28:00 +03:00
if ( boot_ec ! = ec )
2007-03-07 22:28:00 +03:00
kfree ( ec ) ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static acpi_status
2007-03-07 22:28:00 +03:00
ec_parse_io_ports ( struct acpi_resource * resource , void * context )
2005-04-17 02:20:36 +04:00
{
2007-03-07 22:28:00 +03:00
struct acpi_ec * ec = context ;
2005-04-17 02:20:36 +04:00
2007-03-07 22:28:00 +03:00
if ( resource - > type ! = ACPI_RESOURCE_TYPE_IO )
2005-04-17 02:20:36 +04:00
return AE_OK ;
/*
* The first address region returned is the data port , and
* the second address region returned is the status / command
* port .
*/
2007-03-07 22:28:00 +03:00
if ( ec - > data_addr = = 0 )
2006-09-26 19:50:33 +04:00
ec - > data_addr = resource - > data . io . minimum ;
2007-03-07 22:28:00 +03:00
else if ( ec - > command_addr = = 0 )
2006-09-26 19:50:33 +04:00
ec - > command_addr = resource - > data . io . minimum ;
2007-03-07 22:28:00 +03:00
else
2005-04-17 02:20:36 +04:00
return AE_CTRL_TERMINATE ;
return AE_OK ;
}
2007-03-07 22:28:00 +03:00
static int ec_install_handlers ( struct acpi_ec * ec )
{
2007-03-07 22:28:00 +03:00
acpi_status status ;
status = acpi_install_gpe_handler ( NULL , ec - > gpe ,
ACPI_GPE_EDGE_TRIGGERED ,
& acpi_ec_gpe_handler , ec ) ;
2007-03-07 22:28:00 +03:00
if ( ACPI_FAILURE ( status ) )
return - ENODEV ;
2007-03-07 22:28:00 +03:00
2007-03-07 22:28:00 +03:00
acpi_set_gpe_type ( NULL , ec - > gpe , ACPI_GPE_TYPE_RUNTIME ) ;
acpi_enable_gpe ( NULL , ec - > gpe , ACPI_NOT_ISR ) ;
status = acpi_install_address_space_handler ( ec - > handle ,
ACPI_ADR_SPACE_EC ,
& acpi_ec_space_handler ,
& acpi_ec_space_setup , ec ) ;
if ( ACPI_FAILURE ( status ) ) {
acpi_remove_gpe_handler ( NULL , ec - > gpe , & acpi_ec_gpe_handler ) ;
return - ENODEV ;
}
2007-03-07 22:28:00 +03:00
/* EC is fully operational, allow queries */
atomic_set ( & ec - > query_pending , 0 ) ;
2007-03-07 22:28:00 +03:00
return 0 ;
}
2005-08-12 01:32:05 +04:00
static int acpi_ec_start ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2007-03-07 22:28:00 +03:00
struct acpi_ec * ec ;
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
ec = acpi_driver_data ( device ) ;
if ( ! ec )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2006-09-26 19:50:33 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " gpe=0x%02lx, ports=0x%2lx,0x%2lx " ,
2006-12-07 18:42:16 +03:00
ec - > gpe , ec - > command_addr , ec - > data_addr ) ) ;
2005-04-17 02:20:36 +04:00
2007-03-07 22:28:00 +03:00
/* Boot EC is already working */
2007-03-07 22:28:00 +03:00
if ( ec = = boot_ec )
2007-03-07 22:28:00 +03:00
return 0 ;
2007-03-07 22:28:00 +03:00
return ec_install_handlers ( ec ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-12 01:32:05 +04:00
static int acpi_ec_stop ( struct acpi_device * device , int type )
2005-04-17 02:20:36 +04:00
{
2007-03-07 22:28:00 +03:00
acpi_status status ;
struct acpi_ec * ec ;
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
ec = acpi_driver_data ( device ) ;
2007-03-07 22:28:00 +03:00
if ( ! ec )
return - EINVAL ;
/* Don't touch boot EC */
2007-03-07 22:28:00 +03:00
if ( ec = = boot_ec )
2007-03-07 22:28:00 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
2006-09-26 19:50:33 +04:00
status = acpi_remove_address_space_handler ( ec - > handle ,
2005-08-12 01:32:05 +04:00
ACPI_ADR_SPACE_EC ,
& acpi_ec_space_handler ) ;
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
2006-12-07 18:42:17 +03:00
status = acpi_remove_gpe_handler ( NULL , ec - > gpe , & acpi_ec_gpe_handler ) ;
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
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-03-07 22:28:00 +03:00
static acpi_status
ec_parse_device ( acpi_handle handle , u32 Level , void * context , void * * retval )
2005-07-23 12:08:00 +04:00
{
2005-08-12 01:32:05 +04:00
acpi_status status ;
2007-03-07 22:28:00 +03:00
struct acpi_ec * ec = context ;
status = acpi_walk_resources ( handle , METHOD_NAME__CRS ,
ec_parse_io_ports , ec ) ;
if ( ACPI_FAILURE ( status ) )
return status ;
/* Get GPE bit assignment (EC events). */
/* TODO: Add support for _GPE returning a package */
status = acpi_evaluate_integer ( handle , " _GPE " , NULL , & ec - > gpe ) ;
if ( ACPI_FAILURE ( status ) )
return status ;
/* Use the global lock for all EC transactions? */
acpi_evaluate_integer ( handle , " _GLK " , NULL , & ec - > global_lock ) ;
ec - > handle = handle ;
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " GPE=0x%02lx, ports=0x%2lx, 0x%2lx " ,
ec - > gpe , ec - > command_addr , ec - > data_addr ) ) ;
return AE_CTRL_TERMINATE ;
}
int __init acpi_ec_ecdt_probe ( void )
{
int ret ;
acpi_status status ;
2005-08-12 01:32:05 +04:00
struct acpi_table_ecdt * ecdt_ptr ;
2005-07-23 12:08:00 +04:00
2007-03-07 22:28:00 +03:00
boot_ec = make_acpi_ec ( ) ;
if ( ! boot_ec )
2007-03-07 22:28:00 +03:00
return - ENOMEM ;
/*
* Generate a boot ec context
*/
2007-02-02 19:48:22 +03:00
status = acpi_get_table ( ACPI_SIG_ECDT , 1 ,
( struct acpi_table_header * * ) & ecdt_ptr ) ;
2005-07-23 12:08:00 +04:00
if ( ACPI_FAILURE ( status ) )
2007-03-07 22:28:00 +03:00
goto error ;
2005-07-23 12:08:00 +04:00
2006-09-26 19:50:33 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Found ECDT " ) ) ;
2005-07-23 12:08:00 +04:00
2007-03-07 22:28:00 +03:00
boot_ec - > command_addr = ecdt_ptr - > control . address ;
boot_ec - > data_addr = ecdt_ptr - > data . address ;
boot_ec - > gpe = ecdt_ptr - > gpe ;
boot_ec - > handle = ACPI_ROOT_OBJECT ;
2005-04-17 02:20:36 +04:00
2007-03-07 22:28:00 +03:00
ret = ec_install_handlers ( boot_ec ) ;
2007-03-07 22:28:00 +03:00
if ( ! ret ) {
first_ec = boot_ec ;
2007-03-07 22:28:00 +03:00
return 0 ;
2007-03-07 22:28:00 +03:00
}
2007-03-07 22:28:00 +03:00
error :
2007-03-07 22:28:00 +03:00
kfree ( boot_ec ) ;
boot_ec = NULL ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
2005-08-12 01:32:05 +04:00
static int __init acpi_ec_init ( void )
2005-04-17 02:20:36 +04:00
{
2005-08-12 01:32:05 +04:00
int result = 0 ;
2005-04-17 02:20:36 +04:00
if ( acpi_disabled )
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
acpi_ec_dir = proc_mkdir ( ACPI_EC_CLASS , acpi_root_dir ) ;
if ( ! acpi_ec_dir )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
/* Now register the driver for the EC */
result = acpi_bus_register_driver ( & acpi_ec_driver ) ;
if ( result < 0 ) {
remove_proc_entry ( ACPI_EC_CLASS , acpi_root_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 result ;
2005-04-17 02:20:36 +04:00
}
subsys_initcall ( acpi_ec_init ) ;
/* EC driver currently not unloadable */
#if 0
2005-08-12 01:32:05 +04:00
static void __exit acpi_ec_exit ( void )
2005-04-17 02:20:36 +04:00
{
acpi_bus_unregister_driver ( & acpi_ec_driver ) ;
remove_proc_entry ( ACPI_EC_CLASS , acpi_root_dir ) ;
2006-06-27 08:41:40 +04:00
return ;
2005-04-17 02:20:36 +04:00
}
2005-08-12 01:32:05 +04:00
# endif /* 0 */
2005-04-17 02:20:36 +04:00
2005-12-06 00:33:04 +03:00
static int __init acpi_ec_set_intr_mode ( char * str )
2005-07-23 12:08:00 +04:00
{
2005-12-06 00:33:04 +03:00
int intr ;
2005-08-04 01:38:04 +04:00
2005-12-06 00:33:04 +03:00
if ( ! get_option ( & str , & intr ) )
2005-08-04 01:38:04 +04:00
return 0 ;
2007-03-07 22:28:00 +03:00
acpi_ec_mode = ( intr ) ? EC_INTR : EC_POLL ;
2007-03-08 02:29:35 +03:00
printk ( KERN_NOTICE PREFIX " %s mode. \n " , intr ? " interrupt " : " polling " ) ;
2006-09-26 19:50:33 +04:00
2006-03-31 14:30:33 +04:00
return 1 ;
2005-07-23 12:08:00 +04:00
}
2005-08-12 01:32:05 +04:00
2005-12-06 00:46:36 +03:00
__setup ( " ec_intr= " , acpi_ec_set_intr_mode ) ;