2005-04-17 02:20:36 +04:00
/*
* acpi_bus . c - ACPI Bus Driver ( $ Revision : 80 $ )
*
* 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/module.h>
# include <linux/init.h>
# include <linux/ioport.h>
2006-07-12 09:47:00 +04:00
# include <linux/kernel.h>
2005-04-17 02:20:36 +04:00
# include <linux/list.h>
# include <linux/sched.h>
# include <linux/pm.h>
2005-11-14 03:06:25 +03:00
# include <linux/pm_legacy.h>
2005-04-17 02:20:36 +04:00
# include <linux/device.h>
# include <linux/proc_fs.h>
# ifdef CONFIG_X86
# include <asm/mpspec.h>
# endif
# include <acpi/acpi_bus.h>
# include <acpi/acpi_drivers.h>
# define _COMPONENT ACPI_BUS_COMPONENT
2007-02-13 06:42:12 +03:00
ACPI_MODULE_NAME ( " bus " ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_X86
extern void __init acpi_pic_sci_set_trigger ( unsigned int irq , u16 trigger ) ;
# endif
2005-08-05 08:44:28 +04:00
struct acpi_device * acpi_root ;
struct proc_dir_entry * acpi_root_dir ;
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( acpi_root_dir ) ;
# define STRUCT_TO_INT(s) (*((int*)&s))
/* --------------------------------------------------------------------------
Device Management
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2005-08-05 08:44:28 +04:00
int acpi_bus_get_device ( acpi_handle handle , struct acpi_device * * device )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = AE_OK ;
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
/* TBD: Support fixed-feature devices */
2005-08-05 08:44:28 +04:00
status = acpi_get_data ( handle , acpi_bus_data_handler , ( void * * ) device ) ;
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) | | ! * device ) {
2006-07-25 21:30:57 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " No context for object [%p] \n " ,
handle ) ) ;
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
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( acpi_bus_get_device ) ;
2005-08-05 08:44:28 +04:00
int acpi_bus_get_status ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = AE_OK ;
unsigned long sta = 0 ;
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
/*
* Evaluate _STA if present .
*/
if ( device - > flags . dynamic_status ) {
2005-08-05 08:44:28 +04:00
status =
acpi_evaluate_integer ( device - > handle , " _STA " , NULL , & sta ) ;
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-08-05 08:44:28 +04:00
STRUCT_TO_INT ( device - > status ) = ( int ) sta ;
2005-04-17 02:20:36 +04:00
}
/*
* Otherwise we assume the status of our parent ( unless we don ' t
* have one , in which case status is implied ) .
*/
else if ( device - > parent )
device - > status = device - > parent - > status ;
else
2007-04-25 22:20:58 +04:00
STRUCT_TO_INT ( device - > status ) =
ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING ;
2005-04-17 02:20:36 +04:00
if ( device - > status . functional & & ! device - > status . present ) {
printk ( KERN_WARNING PREFIX " Device [%s] status [%08x]: "
2005-08-05 08:44:28 +04:00
" functional but not present; setting present \n " ,
device - > pnp . bus_id , ( u32 ) STRUCT_TO_INT ( device - > status ) ) ;
2005-04-17 02:20:36 +04:00
device - > status . present = 1 ;
}
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Device [%s] status [%08x] \n " ,
device - > pnp . bus_id ,
( u32 ) STRUCT_TO_INT ( device - > status ) ) ) ;
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
EXPORT_SYMBOL ( acpi_bus_get_status ) ;
2005-04-17 02:20:36 +04:00
/* --------------------------------------------------------------------------
Power Management
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2005-08-05 08:44:28 +04:00
int acpi_bus_get_power ( acpi_handle handle , int * state )
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_device * device = NULL ;
unsigned long psc = 0 ;
2005-04-17 02:20:36 +04:00
result = acpi_bus_get_device ( handle , & device ) ;
if ( result )
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
* state = ACPI_STATE_UNKNOWN ;
if ( ! device - > flags . power_manageable ) {
/* TBD: Non-recursive algorithm for walking up hierarchy */
if ( device - > parent )
* state = device - > parent - > power . state ;
else
* state = ACPI_STATE_D0 ;
2005-08-05 08:44:28 +04:00
} else {
2005-04-17 02:20:36 +04:00
/*
2007-02-10 09:32:16 +03:00
* Get the device ' s power state either directly ( via _PSC ) or
2005-04-17 02:20:36 +04:00
* indirectly ( via power resources ) .
*/
if ( device - > power . flags . explicit_get ) {
2005-08-05 08:44:28 +04:00
status = acpi_evaluate_integer ( device - > handle , " _PSC " ,
NULL , & psc ) ;
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-08-05 08:44:28 +04:00
device - > power . state = ( int ) psc ;
} else if ( device - > power . flags . power_resources ) {
2005-04-17 02:20:36 +04:00
result = acpi_power_get_inferred_state ( device ) ;
if ( result )
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
* state = device - > power . state ;
}
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Device [%s] power state is D%d \n " ,
2005-08-05 08:44:28 +04:00
device - > pnp . bus_id , device - > power . state ) ) ;
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
EXPORT_SYMBOL ( acpi_bus_get_power ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
int acpi_bus_set_power ( acpi_handle handle , int state )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
acpi_status status = AE_OK ;
struct acpi_device * device = NULL ;
char object_name [ 5 ] = { ' _ ' , ' P ' , ' S ' , ' 0 ' + state , ' \0 ' } ;
2005-04-17 02:20:36 +04:00
result = acpi_bus_get_device ( handle , & device ) ;
if ( result )
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
if ( ( state < ACPI_STATE_D0 ) | | ( state > ACPI_STATE_D3 ) )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
/* Make sure this is a valid target state */
if ( ! device - > flags . power_manageable ) {
2006-07-25 21:30:57 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Device `[%s]' is not power manageable \n " ,
2006-12-07 15:56:38 +03:00
device - > dev . kobj . name ) ) ;
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2005-03-19 08:16:18 +03:00
/*
* Get device ' s current power state if it ' s unknown
* This means device power state isn ' t initialized or previous setting failed
*/
2007-02-16 10:23:07 +03:00
if ( ( device - > power . state = = ACPI_STATE_UNKNOWN ) | | device - > flags . force_power_state )
acpi_bus_get_power ( device - > handle , & device - > power . state ) ;
if ( ( state = = device - > power . state ) & & ! device - > flags . force_power_state ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Device is already at D%d \n " ,
state ) ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-02-16 10:23:07 +03:00
2005-04-17 02:20:36 +04:00
if ( ! device - > power . states [ state ] . flags . valid ) {
2006-06-27 07:04:31 +04:00
printk ( KERN_WARNING PREFIX " Device does not support D%d \n " , state ) ;
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
if ( device - > parent & & ( state < device - > parent - > power . state ) ) {
2006-06-27 07:04:31 +04:00
printk ( KERN_WARNING PREFIX
2006-06-27 07:58:43 +04:00
" Cannot set device to a higher-powered "
2006-06-27 07:04:31 +04:00
" state than parent \n " ) ;
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
/*
* Transition Power
* - - - - - - - - - - - - - - - -
* On transitions to a high - powered state we first apply power ( via
* power resources ) then evalute _PSx . Conversly for transitions to
* a lower - powered state .
2005-03-19 08:16:18 +03:00
*/
2005-04-17 02:20:36 +04:00
if ( state < device - > power . state ) {
if ( device - > power . flags . power_resources ) {
result = acpi_power_transition ( device , state ) ;
if ( result )
goto end ;
}
if ( device - > power . states [ state ] . flags . explicit_set ) {
2005-08-05 08:44:28 +04:00
status = acpi_evaluate_object ( device - > handle ,
object_name , NULL , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) ) {
result = - ENODEV ;
goto end ;
}
}
2005-08-05 08:44:28 +04:00
} else {
2005-04-17 02:20:36 +04:00
if ( device - > power . states [ state ] . flags . explicit_set ) {
2005-08-05 08:44:28 +04:00
status = acpi_evaluate_object ( device - > handle ,
object_name , NULL , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) ) {
result = - ENODEV ;
goto end ;
}
}
if ( device - > power . flags . power_resources ) {
result = acpi_power_transition ( device , state ) ;
if ( result )
goto end ;
}
}
2005-08-05 08:44:28 +04:00
end :
2005-04-17 02:20:36 +04:00
if ( result )
2006-06-27 07:04:31 +04:00
printk ( KERN_WARNING PREFIX
" Transitioning device [%s] to D%d \n " ,
device - > pnp . bus_id , state ) ;
2007-10-12 01:53:58 +04:00
else {
device - > power . state = state ;
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" Device [%s] transitioned to D%d \n " ,
device - > pnp . bus_id , state ) ) ;
2007-10-12 01:53:58 +04:00
}
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
}
2005-08-05 08:44:28 +04:00
EXPORT_SYMBOL ( acpi_bus_set_power ) ;
2005-04-17 02:20:36 +04:00
/* --------------------------------------------------------------------------
Event Management
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-08-23 23:20:26 +04:00
# ifdef CONFIG_ACPI_PROC_EVENT
2005-04-17 02:20:36 +04:00
static DEFINE_SPINLOCK ( acpi_bus_event_lock ) ;
LIST_HEAD ( acpi_bus_event_list ) ;
DECLARE_WAIT_QUEUE_HEAD ( acpi_bus_event_queue ) ;
2005-08-05 08:44:28 +04:00
extern int event_is_open ;
2005-04-17 02:20:36 +04:00
2007-08-23 23:20:26 +04:00
int acpi_bus_generate_proc_event ( struct acpi_device * device , u8 type , int data )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
struct acpi_bus_event * event = NULL ;
unsigned long flags = 0 ;
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
/* drop event on the floor if no one's listening */
if ( ! event_is_open )
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
event = kmalloc ( sizeof ( struct acpi_bus_event ) , GFP_ATOMIC ) ;
if ( ! event )
2006-06-27 08:41:40 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
strcpy ( event - > device_class , device - > pnp . device_class ) ;
strcpy ( event - > bus_id , device - > pnp . bus_id ) ;
event - > type = type ;
event - > data = data ;
spin_lock_irqsave ( & acpi_bus_event_lock , flags ) ;
list_add_tail ( & event - > node , & acpi_bus_event_list ) ;
spin_unlock_irqrestore ( & acpi_bus_event_lock , flags ) ;
wake_up_interruptible ( & acpi_bus_event_queue ) ;
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
2007-08-23 23:20:26 +04:00
EXPORT_SYMBOL ( acpi_bus_generate_proc_event ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
int acpi_bus_receive_event ( struct acpi_bus_event * event )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
unsigned long flags = 0 ;
struct acpi_bus_event * entry = NULL ;
2005-04-17 02:20:36 +04:00
DECLARE_WAITQUEUE ( wait , current ) ;
if ( ! event )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( list_empty ( & acpi_bus_event_list ) ) {
set_current_state ( TASK_INTERRUPTIBLE ) ;
add_wait_queue ( & acpi_bus_event_queue , & wait ) ;
if ( list_empty ( & acpi_bus_event_list ) )
schedule ( ) ;
remove_wait_queue ( & acpi_bus_event_queue , & wait ) ;
set_current_state ( TASK_RUNNING ) ;
if ( signal_pending ( current ) )
2006-06-27 08:41:40 +04:00
return - ERESTARTSYS ;
2005-04-17 02:20:36 +04:00
}
spin_lock_irqsave ( & acpi_bus_event_lock , flags ) ;
2005-08-05 08:44:28 +04:00
entry =
list_entry ( acpi_bus_event_list . next , struct acpi_bus_event , node ) ;
2005-04-17 02:20:36 +04:00
if ( entry )
list_del ( & entry - > node ) ;
spin_unlock_irqrestore ( & acpi_bus_event_lock , flags ) ;
if ( ! entry )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
memcpy ( event , entry , sizeof ( struct acpi_bus_event ) ) ;
kfree ( entry ) ;
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
EXPORT_SYMBOL ( acpi_bus_receive_event ) ;
2007-08-23 23:20:26 +04:00
# endif /* CONFIG_ACPI_PROC_EVENT */
2005-04-17 02:20:36 +04:00
/* --------------------------------------------------------------------------
Notification Handling
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
2005-08-05 08:44:28 +04:00
acpi_bus_check_device ( struct acpi_device * device , int * status_changed )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = 0 ;
2005-04-17 02:20:36 +04:00
struct acpi_device_status old_status ;
if ( ! device )
2006-06-27 08:41:40 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( status_changed )
* status_changed = 0 ;
old_status = device - > status ;
/*
* Make sure this device ' s parent is present before we go about
* messing with the device .
*/
if ( device - > parent & & ! device - > parent - > status . present ) {
device - > status = device - > parent - > status ;
if ( STRUCT_TO_INT ( old_status ) ! = STRUCT_TO_INT ( device - > status ) ) {
if ( status_changed )
* status_changed = 1 ;
}
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
status = acpi_bus_get_status ( device ) ;
if ( ACPI_FAILURE ( status ) )
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
if ( STRUCT_TO_INT ( old_status ) = = STRUCT_TO_INT ( device - > status ) )
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
if ( status_changed )
* status_changed = 1 ;
2005-08-05 08:44:28 +04:00
2005-04-17 02:20:36 +04:00
/*
* Device Insertion / Removal
*/
if ( ( device - > status . present ) & & ! ( old_status . present ) ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Device insertion detected \n " ) ) ;
/* TBD: Handle device insertion */
2005-08-05 08:44:28 +04:00
} else if ( ! ( device - > status . present ) & & ( old_status . present ) ) {
2005-04-17 02:20:36 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Device removal detected \n " ) ) ;
/* TBD: Handle device removal */
}
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_bus_check_scope ( struct acpi_device * device )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
int status_changed = 0 ;
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
/* Status Change? */
result = acpi_bus_check_device ( device , & status_changed ) ;
if ( result )
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
if ( ! status_changed )
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
/*
* TBD : Enumerate child devices within this device ' s scope and
* run acpi_bus_check_device ( ) ' s on them .
*/
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/**
* acpi_bus_notify
* - - - - - - - - - - - - - - -
* Callback for all ' system - level ' device notifications ( values 0x00 - 0x7F ) .
*/
2005-08-05 08:44:28 +04:00
static void acpi_bus_notify ( acpi_handle handle , u32 type , void * data )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
struct acpi_device * device = NULL ;
2005-04-17 02:20:36 +04:00
if ( acpi_bus_get_device ( handle , & device ) )
2006-06-27 08:41:40 +04:00
return ;
2005-04-17 02:20:36 +04:00
switch ( type ) {
case ACPI_NOTIFY_BUS_CHECK :
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" Received BUS CHECK notification for device [%s] \n " ,
device - > pnp . bus_id ) ) ;
2005-04-17 02:20:36 +04:00
result = acpi_bus_check_scope ( device ) ;
2007-02-10 09:32:16 +03:00
/*
2005-04-17 02:20:36 +04:00
* TBD : We ' ll need to outsource certain events to non - ACPI
2005-08-05 08:44:28 +04:00
* drivers via the device manager ( device . c ) .
2005-04-17 02:20:36 +04:00
*/
break ;
case ACPI_NOTIFY_DEVICE_CHECK :
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" Received DEVICE CHECK notification for device [%s] \n " ,
device - > pnp . bus_id ) ) ;
2005-04-17 02:20:36 +04:00
result = acpi_bus_check_device ( device , NULL ) ;
2007-02-10 09:32:16 +03:00
/*
2005-04-17 02:20:36 +04:00
* TBD : We ' ll need to outsource certain events to non - ACPI
2005-08-05 08:44:28 +04:00
* drivers via the device manager ( device . c ) .
2005-04-17 02:20:36 +04:00
*/
break ;
case ACPI_NOTIFY_DEVICE_WAKE :
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" Received DEVICE WAKE notification for device [%s] \n " ,
device - > pnp . bus_id ) ) ;
2005-04-17 02:20:36 +04:00
/* TBD */
break ;
case ACPI_NOTIFY_EJECT_REQUEST :
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" Received EJECT REQUEST notification for device [%s] \n " ,
device - > pnp . bus_id ) ) ;
2005-04-17 02:20:36 +04:00
/* TBD */
break ;
case ACPI_NOTIFY_DEVICE_CHECK_LIGHT :
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" Received DEVICE CHECK LIGHT notification for device [%s] \n " ,
device - > pnp . bus_id ) ) ;
2005-04-17 02:20:36 +04:00
/* TBD: Exactly what does 'light' mean? */
break ;
case ACPI_NOTIFY_FREQUENCY_MISMATCH :
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" Received FREQUENCY MISMATCH notification for device [%s] \n " ,
device - > pnp . bus_id ) ) ;
2005-04-17 02:20:36 +04:00
/* TBD */
break ;
case ACPI_NOTIFY_BUS_MODE_MISMATCH :
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" Received BUS MODE MISMATCH notification for device [%s] \n " ,
device - > pnp . bus_id ) ) ;
2005-04-17 02:20:36 +04:00
/* TBD */
break ;
case ACPI_NOTIFY_POWER_FAULT :
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" Received POWER FAULT notification for device [%s] \n " ,
device - > pnp . bus_id ) ) ;
2005-04-17 02:20:36 +04:00
/* TBD */
break ;
default :
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" Received unknown/unsupported notification [%08x] \n " ,
type ) ) ;
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
}
/* --------------------------------------------------------------------------
Initialization / Cleanup
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2005-08-05 08:44:28 +04:00
static int __init acpi_bus_init_irq ( void )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = AE_OK ;
union acpi_object arg = { ACPI_TYPE_INTEGER } ;
struct acpi_object_list arg_list = { 1 , & arg } ;
char * message = NULL ;
2005-04-17 02:20:36 +04:00
2007-02-10 09:32:16 +03:00
/*
2005-04-17 02:20:36 +04:00
* Let the system know what interrupt model we are using by
* evaluating the \ _PIC object , if exists .
*/
switch ( acpi_irq_model ) {
case ACPI_IRQ_MODEL_PIC :
message = " PIC " ;
break ;
case ACPI_IRQ_MODEL_IOAPIC :
message = " IOAPIC " ;
break ;
case ACPI_IRQ_MODEL_IOSAPIC :
message = " IOSAPIC " ;
break ;
2006-12-22 20:50:04 +03:00
case ACPI_IRQ_MODEL_PLATFORM :
message = " platform specific model " ;
break ;
2005-04-17 02:20:36 +04:00
default :
printk ( KERN_WARNING PREFIX " Unknown interrupt routing model \n " ) ;
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
printk ( KERN_INFO PREFIX " Using %s for interrupt routing \n " , message ) ;
arg . integer . value = acpi_irq_model ;
status = acpi_evaluate_object ( NULL , " \\ _PIC " , & arg_list , NULL ) ;
if ( ACPI_FAILURE ( status ) & & ( status ! = AE_NOT_FOUND ) ) {
2006-06-27 07:58:43 +04:00
ACPI_EXCEPTION ( ( AE_INFO , status , " Evaluating _PIC " ) ) ;
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-02-02 19:48:19 +03:00
acpi_native_uint acpi_gbl_permanent_mmap ;
2005-08-05 08:44:28 +04:00
void __init acpi_early_init ( void )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = AE_OK ;
2005-04-17 02:20:36 +04:00
if ( acpi_disabled )
2006-06-27 08:41:40 +04:00
return ;
2005-04-17 02:20:36 +04:00
2006-03-18 00:44:00 +03:00
printk ( KERN_INFO PREFIX " Core revision %08x \n " , ACPI_CA_VERSION ) ;
2005-04-17 02:20:36 +04:00
/* enable workarounds, unless strict ACPI spec. compliance */
if ( ! acpi_strict )
acpi_gbl_enable_interpreter_slack = TRUE ;
2007-02-02 19:48:19 +03:00
acpi_gbl_permanent_mmap = 1 ;
status = acpi_reallocate_root_table ( ) ;
if ( ACPI_FAILURE ( status ) ) {
printk ( KERN_ERR PREFIX
" Unable to reallocate ACPI tables \n " ) ;
goto error0 ;
}
2005-04-17 02:20:36 +04:00
status = acpi_initialize_subsystem ( ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-08-05 08:44:28 +04:00
printk ( KERN_ERR PREFIX
" Unable to initialize the ACPI Interpreter \n " ) ;
2005-04-17 02:20:36 +04:00
goto error0 ;
}
status = acpi_load_tables ( ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-08-05 08:44:28 +04:00
printk ( KERN_ERR PREFIX
" Unable to load the System Description Tables \n " ) ;
2005-04-17 02:20:36 +04:00
goto error0 ;
}
# ifdef CONFIG_X86
if ( ! acpi_ioapic ) {
2007-02-02 19:48:22 +03:00
extern u8 acpi_sci_flags ;
2005-04-17 02:20:36 +04:00
/* compatible (0) means level (3) */
2007-02-02 19:48:22 +03:00
if ( ! ( acpi_sci_flags & ACPI_MADT_TRIGGER_MASK ) ) {
acpi_sci_flags & = ~ ACPI_MADT_TRIGGER_MASK ;
acpi_sci_flags | = ACPI_MADT_TRIGGER_LEVEL ;
}
2005-04-17 02:20:36 +04:00
/* Set PIC-mode SCI trigger type */
2007-02-02 19:48:22 +03:00
acpi_pic_sci_set_trigger ( acpi_gbl_FADT . sci_interrupt ,
2007-02-02 19:48:22 +03:00
( acpi_sci_flags & ACPI_MADT_TRIGGER_MASK ) > > 2 ) ;
2005-04-17 02:20:36 +04:00
} else {
extern int acpi_sci_override_gsi ;
/*
2007-02-02 19:48:22 +03:00
* now that acpi_gbl_FADT is initialized ,
2005-04-17 02:20:36 +04:00
* update it with result from INT_SRC_OVR parsing
*/
2007-02-02 19:48:22 +03:00
acpi_gbl_FADT . sci_interrupt = acpi_sci_override_gsi ;
2005-04-17 02:20:36 +04:00
}
# endif
2005-08-05 08:44:28 +04:00
status =
acpi_enable_subsystem ( ~
( ACPI_NO_HARDWARE_INIT |
ACPI_NO_ACPI_ENABLE ) ) ;
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) ) {
printk ( KERN_ERR PREFIX " Unable to enable ACPI \n " ) ;
goto error0 ;
}
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
error0 :
2005-04-17 02:20:36 +04:00
disable_acpi ( ) ;
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 __init acpi_bus_init ( void )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
acpi_status status = AE_OK ;
extern acpi_status acpi_os_initialize1 ( void ) ;
2005-04-17 02:20:36 +04:00
status = acpi_os_initialize1 ( ) ;
2005-08-05 08:44:28 +04:00
status =
acpi_enable_subsystem ( ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE ) ;
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) ) {
2005-08-05 08:44:28 +04:00
printk ( KERN_ERR PREFIX
" Unable to start the ACPI Interpreter \n " ) ;
2005-04-17 02:20:36 +04:00
goto error1 ;
}
if ( ACPI_FAILURE ( status ) ) {
2005-08-05 08:44:28 +04:00
printk ( KERN_ERR PREFIX
" Unable to initialize ACPI OS objects \n " ) ;
2005-04-17 02:20:36 +04:00
goto error1 ;
}
# ifdef CONFIG_ACPI_EC
/*
* ACPI 2.0 requires the EC driver to be loaded and work before
* the EC device is found in the namespace ( i . e . before acpi_initialize_objects ( )
* is called ) .
*
2007-02-10 09:32:16 +03:00
* This is accomplished by looking for the ECDT table , and getting
2005-04-17 02:20:36 +04:00
* the EC parameters out of that .
*/
status = acpi_ec_ecdt_probe ( ) ;
/* Ignore result. Not having an ECDT is not fatal. */
# endif
status = acpi_initialize_objects ( ACPI_FULL_INITIALIZATION ) ;
if ( ACPI_FAILURE ( status ) ) {
printk ( KERN_ERR PREFIX " Unable to initialize ACPI objects \n " ) ;
goto error1 ;
}
printk ( KERN_INFO PREFIX " Interpreter enabled \n " ) ;
2007-02-10 09:32:16 +03:00
/* Initialize sleep structures */
acpi_sleep_init ( ) ;
2005-04-17 02:20:36 +04:00
/*
* Get the system interrupt model and evaluate \ _PIC .
*/
result = acpi_bus_init_irq ( ) ;
if ( result )
goto error1 ;
/*
* Register the for all standard device notifications .
*/
2005-08-05 08:44:28 +04:00
status =
acpi_install_notify_handler ( ACPI_ROOT_OBJECT , ACPI_SYSTEM_NOTIFY ,
& acpi_bus_notify , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) ) {
2005-08-05 08:44:28 +04:00
printk ( KERN_ERR PREFIX
" Unable to register for device notifications \n " ) ;
2005-04-17 02:20:36 +04:00
goto error1 ;
}
/*
* Create the top ACPI proc directory
*/
acpi_root_dir = proc_mkdir ( ACPI_BUS_FILE_ROOT , NULL ) ;
2006-06-27 08:41:40 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
/* Mimic structured exception handling */
2005-08-05 08:44:28 +04:00
error1 :
2005-04-17 02:20:36 +04:00
acpi_terminate ( ) ;
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
decl_subsys ( acpi , NULL , NULL ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
static int __init acpi_init ( void )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
int result = 0 ;
2005-04-17 02:20:36 +04:00
if ( acpi_disabled ) {
printk ( KERN_INFO PREFIX " Interpreter disabled. \n " ) ;
2006-06-27 08:41:40 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2006-07-12 09:47:00 +04:00
result = firmware_register ( & acpi_subsys ) ;
if ( result < 0 )
printk ( KERN_WARNING " %s: firmware_register error: %d \n " ,
__FUNCTION__ , result ) ;
2005-04-17 02:20:36 +04:00
result = acpi_bus_init ( ) ;
if ( ! result ) {
2005-11-14 03:06:25 +03:00
# ifdef CONFIG_PM_LEGACY
2005-04-17 02:20:36 +04:00
if ( ! PM_IS_ACTIVE ( ) )
pm_active = 1 ;
else {
2005-08-05 08:44:28 +04:00
printk ( KERN_INFO PREFIX
" APM is already active, exiting \n " ) ;
2005-04-17 02:20:36 +04:00
disable_acpi ( ) ;
result = - ENODEV ;
}
# endif
} else
disable_acpi ( ) ;
2006-06-27 08:41:40 +04:00
return result ;
2005-04-17 02:20:36 +04:00
}
subsys_initcall ( acpi_init ) ;