2005-04-17 06:20:36 +08:00
/******************************************************************************
*
* Module Name : evgpe - General Purpose Event handling and dispatch
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Copyright ( C ) 2000 - 2005 , R . Byron Moore
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions , and the following disclaimer ,
* without modification .
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* substantially similar to the " NO WARRANTY " disclaimer below
* ( " Disclaimer " ) and any redistribution must be conditioned upon
* including a substantially similar Disclaimer requirement for further
* binary redistribution .
* 3. Neither the names of the above - listed copyright holders nor the names
* of any contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
*
* Alternatively , this software may be distributed under the terms of the
* GNU General Public License ( " GPL " ) version 2 as published by the Free
* Software Foundation .
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT ,
* STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES .
*/
# include <acpi/acpi.h>
# include <acpi/acevents.h>
# include <acpi/acnamesp.h>
# define _COMPONENT ACPI_EVENTS
2005-08-05 12:44:28 +08:00
ACPI_MODULE_NAME ( " evgpe " )
2005-04-17 06:20:36 +08:00
2005-04-19 10:49:35 +08:00
/* Local prototypes */
2005-08-05 12:44:28 +08:00
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method ( void * context ) ;
2005-04-17 06:20:36 +08:00
/*******************************************************************************
*
* FUNCTION : acpi_ev_set_gpe_type
*
* PARAMETERS : gpe_event_info - GPE to set
* Type - New type
*
* RETURN : Status
*
* DESCRIPTION : Sets the new type for the GPE ( wake , run , or wake / run )
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status
2005-08-05 12:44:28 +08:00
acpi_ev_set_gpe_type ( struct acpi_gpe_event_info * gpe_event_info , u8 type )
2005-04-17 06:20:36 +08:00
{
2005-08-05 12:44:28 +08:00
acpi_status status ;
2005-04-17 06:20:36 +08:00
2005-08-05 12:44:28 +08:00
ACPI_FUNCTION_TRACE ( " ev_set_gpe_type " ) ;
2005-04-17 06:20:36 +08:00
/* Validate type and update register enable masks */
switch ( type ) {
case ACPI_GPE_TYPE_WAKE :
case ACPI_GPE_TYPE_RUNTIME :
case ACPI_GPE_TYPE_WAKE_RUN :
break ;
default :
2005-08-05 12:44:28 +08:00
return_ACPI_STATUS ( AE_BAD_PARAMETER ) ;
2005-04-17 06:20:36 +08:00
}
/* Disable the GPE if currently enabled */
2005-08-05 12:44:28 +08:00
status = acpi_ev_disable_gpe ( gpe_event_info ) ;
2005-04-17 06:20:36 +08:00
/* Type was validated above */
2005-08-05 12:44:28 +08:00
gpe_event_info - > flags & = ~ ACPI_GPE_TYPE_MASK ; /* Clear type bits */
gpe_event_info - > flags | = type ; /* Insert type */
return_ACPI_STATUS ( status ) ;
2005-04-17 06:20:36 +08:00
}
/*******************************************************************************
*
* FUNCTION : acpi_ev_update_gpe_enable_masks
*
* PARAMETERS : gpe_event_info - GPE to update
* Type - What to do : ACPI_GPE_DISABLE or
* ACPI_GPE_ENABLE
*
* RETURN : Status
*
* DESCRIPTION : Updates GPE register enable masks based on the GPE type
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status
2005-08-05 12:44:28 +08:00
acpi_ev_update_gpe_enable_masks ( struct acpi_gpe_event_info * gpe_event_info ,
u8 type )
2005-04-17 06:20:36 +08:00
{
2005-08-05 12:44:28 +08:00
struct acpi_gpe_register_info * gpe_register_info ;
u8 register_bit ;
2005-04-17 06:20:36 +08:00
2005-08-05 12:44:28 +08:00
ACPI_FUNCTION_TRACE ( " ev_update_gpe_enable_masks " ) ;
2005-04-17 06:20:36 +08:00
gpe_register_info = gpe_event_info - > register_info ;
if ( ! gpe_register_info ) {
2005-08-05 12:44:28 +08:00
return_ACPI_STATUS ( AE_NOT_EXIST ) ;
2005-04-17 06:20:36 +08:00
}
register_bit = gpe_event_info - > register_bit ;
/* 1) Disable case. Simply clear all enable bits */
if ( type = = ACPI_GPE_DISABLE ) {
2005-08-05 12:44:28 +08:00
ACPI_CLEAR_BIT ( gpe_register_info - > enable_for_wake ,
register_bit ) ;
ACPI_CLEAR_BIT ( gpe_register_info - > enable_for_run , register_bit ) ;
return_ACPI_STATUS ( AE_OK ) ;
2005-04-17 06:20:36 +08:00
}
/* 2) Enable case. Set/Clear the appropriate enable bits */
switch ( gpe_event_info - > flags & ACPI_GPE_TYPE_MASK ) {
case ACPI_GPE_TYPE_WAKE :
2005-08-05 12:44:28 +08:00
ACPI_SET_BIT ( gpe_register_info - > enable_for_wake , register_bit ) ;
ACPI_CLEAR_BIT ( gpe_register_info - > enable_for_run , register_bit ) ;
2005-04-17 06:20:36 +08:00
break ;
case ACPI_GPE_TYPE_RUNTIME :
2005-08-05 12:44:28 +08:00
ACPI_CLEAR_BIT ( gpe_register_info - > enable_for_wake ,
register_bit ) ;
ACPI_SET_BIT ( gpe_register_info - > enable_for_run , register_bit ) ;
2005-04-17 06:20:36 +08:00
break ;
case ACPI_GPE_TYPE_WAKE_RUN :
2005-08-05 12:44:28 +08:00
ACPI_SET_BIT ( gpe_register_info - > enable_for_wake , register_bit ) ;
ACPI_SET_BIT ( gpe_register_info - > enable_for_run , register_bit ) ;
2005-04-17 06:20:36 +08:00
break ;
default :
2005-08-05 12:44:28 +08:00
return_ACPI_STATUS ( AE_BAD_PARAMETER ) ;
2005-04-17 06:20:36 +08:00
}
2005-08-05 12:44:28 +08:00
return_ACPI_STATUS ( AE_OK ) ;
2005-04-17 06:20:36 +08:00
}
/*******************************************************************************
*
* FUNCTION : acpi_ev_enable_gpe
*
* PARAMETERS : gpe_event_info - GPE to enable
* write_to_hardware - Enable now , or just mark data structs
* ( WAKE GPEs should be deferred )
*
* RETURN : Status
*
* DESCRIPTION : Enable a GPE based on the GPE type
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status
2005-08-05 12:44:28 +08:00
acpi_ev_enable_gpe ( struct acpi_gpe_event_info * gpe_event_info ,
u8 write_to_hardware )
2005-04-17 06:20:36 +08:00
{
2005-08-05 12:44:28 +08:00
acpi_status status ;
2005-04-17 06:20:36 +08:00
2005-08-05 12:44:28 +08:00
ACPI_FUNCTION_TRACE ( " ev_enable_gpe " ) ;
2005-04-17 06:20:36 +08:00
/* Make sure HW enable masks are updated */
2005-08-05 12:44:28 +08:00
status =
acpi_ev_update_gpe_enable_masks ( gpe_event_info , ACPI_GPE_ENABLE ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-17 06:20:36 +08:00
}
/* Mark wake-enabled or HW enable, or both */
switch ( gpe_event_info - > flags & ACPI_GPE_TYPE_MASK ) {
case ACPI_GPE_TYPE_WAKE :
2005-08-05 12:44:28 +08:00
ACPI_SET_BIT ( gpe_event_info - > flags , ACPI_GPE_WAKE_ENABLED ) ;
2005-04-17 06:20:36 +08:00
break ;
case ACPI_GPE_TYPE_WAKE_RUN :
2005-08-05 12:44:28 +08:00
ACPI_SET_BIT ( gpe_event_info - > flags , ACPI_GPE_WAKE_ENABLED ) ;
2005-04-17 06:20:36 +08:00
/*lint -fallthrough */
case ACPI_GPE_TYPE_RUNTIME :
2005-08-05 12:44:28 +08:00
ACPI_SET_BIT ( gpe_event_info - > flags , ACPI_GPE_RUN_ENABLED ) ;
2005-04-17 06:20:36 +08:00
if ( write_to_hardware ) {
/* Clear the GPE (of stale events), then enable it */
2005-08-05 12:44:28 +08:00
status = acpi_hw_clear_gpe ( gpe_event_info ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-17 06:20:36 +08:00
}
/* Enable the requested runtime GPE */
2005-08-05 12:44:28 +08:00
status = acpi_hw_write_gpe_enable_reg ( gpe_event_info ) ;
2005-04-17 06:20:36 +08:00
}
break ;
default :
2005-08-05 12:44:28 +08:00
return_ACPI_STATUS ( AE_BAD_PARAMETER ) ;
2005-04-17 06:20:36 +08:00
}
2005-08-05 12:44:28 +08:00
return_ACPI_STATUS ( AE_OK ) ;
2005-04-17 06:20:36 +08:00
}
/*******************************************************************************
*
* FUNCTION : acpi_ev_disable_gpe
*
* PARAMETERS : gpe_event_info - GPE to disable
*
* RETURN : Status
*
* DESCRIPTION : Disable a GPE based on the GPE type
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-08-05 12:44:28 +08:00
acpi_status acpi_ev_disable_gpe ( struct acpi_gpe_event_info * gpe_event_info )
2005-04-17 06:20:36 +08:00
{
2005-08-05 12:44:28 +08:00
acpi_status status ;
2005-04-17 06:20:36 +08:00
2005-08-05 12:44:28 +08:00
ACPI_FUNCTION_TRACE ( " ev_disable_gpe " ) ;
2005-04-17 06:20:36 +08:00
if ( ! ( gpe_event_info - > flags & ACPI_GPE_ENABLE_MASK ) ) {
2005-08-05 12:44:28 +08:00
return_ACPI_STATUS ( AE_OK ) ;
2005-04-17 06:20:36 +08:00
}
/* Make sure HW enable masks are updated */
2005-08-05 12:44:28 +08:00
status =
acpi_ev_update_gpe_enable_masks ( gpe_event_info , ACPI_GPE_DISABLE ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-17 06:20:36 +08:00
}
/* Mark wake-disabled or HW disable, or both */
switch ( gpe_event_info - > flags & ACPI_GPE_TYPE_MASK ) {
case ACPI_GPE_TYPE_WAKE :
2005-08-05 12:44:28 +08:00
ACPI_CLEAR_BIT ( gpe_event_info - > flags , ACPI_GPE_WAKE_ENABLED ) ;
2005-04-17 06:20:36 +08:00
break ;
case ACPI_GPE_TYPE_WAKE_RUN :
2005-08-05 12:44:28 +08:00
ACPI_CLEAR_BIT ( gpe_event_info - > flags , ACPI_GPE_WAKE_ENABLED ) ;
2005-04-17 06:20:36 +08:00
/*lint -fallthrough */
case ACPI_GPE_TYPE_RUNTIME :
/* Disable the requested runtime GPE */
2005-08-05 12:44:28 +08:00
ACPI_CLEAR_BIT ( gpe_event_info - > flags , ACPI_GPE_RUN_ENABLED ) ;
status = acpi_hw_write_gpe_enable_reg ( gpe_event_info ) ;
2005-04-17 06:20:36 +08:00
break ;
default :
2005-08-05 12:44:28 +08:00
return_ACPI_STATUS ( AE_BAD_PARAMETER ) ;
2005-04-17 06:20:36 +08:00
}
2005-08-05 12:44:28 +08:00
return_ACPI_STATUS ( AE_OK ) ;
2005-04-17 06:20:36 +08:00
}
/*******************************************************************************
*
* FUNCTION : acpi_ev_get_gpe_event_info
*
* PARAMETERS : gpe_device - Device node . NULL for GPE0 / GPE1
* gpe_number - Raw GPE number
*
* RETURN : A GPE event_info struct . NULL if not a valid GPE
*
* DESCRIPTION : Returns the event_info struct associated with this GPE .
* Validates the gpe_block and the gpe_number
*
* Should be called only when the GPE lists are semaphore locked
* and not subject to change .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-08-05 12:44:28 +08:00
struct acpi_gpe_event_info * acpi_ev_get_gpe_event_info ( acpi_handle gpe_device ,
u32 gpe_number )
2005-04-17 06:20:36 +08:00
{
2005-08-05 12:44:28 +08:00
union acpi_operand_object * obj_desc ;
struct acpi_gpe_block_info * gpe_block ;
acpi_native_uint i ;
2005-04-17 06:20:36 +08:00
2005-08-05 12:44:28 +08:00
ACPI_FUNCTION_ENTRY ( ) ;
2005-04-17 06:20:36 +08:00
/* A NULL gpe_block means use the FADT-defined GPE block(s) */
if ( ! gpe_device ) {
/* Examine GPE Block 0 and 1 (These blocks are permanent) */
for ( i = 0 ; i < ACPI_MAX_GPE_BLOCKS ; i + + ) {
gpe_block = acpi_gbl_gpe_fadt_blocks [ i ] ;
if ( gpe_block ) {
2005-08-05 12:44:28 +08:00
if ( ( gpe_number > = gpe_block - > block_base_number )
& & ( gpe_number <
gpe_block - > block_base_number +
( gpe_block - > register_count * 8 ) ) ) {
return ( & gpe_block - >
event_info [ gpe_number -
gpe_block - >
block_base_number ] ) ;
2005-04-17 06:20:36 +08:00
}
}
}
/* The gpe_number was not in the range of either FADT GPE block */
return ( NULL ) ;
}
/* A Non-NULL gpe_device means this is a GPE Block Device */
2005-08-05 12:44:28 +08:00
obj_desc =
acpi_ns_get_attached_object ( ( struct acpi_namespace_node * )
gpe_device ) ;
if ( ! obj_desc | | ! obj_desc - > device . gpe_block ) {
2005-04-17 06:20:36 +08:00
return ( NULL ) ;
}
gpe_block = obj_desc - > device . gpe_block ;
if ( ( gpe_number > = gpe_block - > block_base_number ) & &
2005-08-05 12:44:28 +08:00
( gpe_number <
gpe_block - > block_base_number + ( gpe_block - > register_count * 8 ) ) ) {
return ( & gpe_block - >
event_info [ gpe_number - gpe_block - > block_base_number ] ) ;
2005-04-17 06:20:36 +08:00
}
return ( NULL ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_ev_gpe_detect
*
* PARAMETERS : gpe_xrupt_list - Interrupt block for this interrupt .
* Can have multiple GPE blocks attached .
*
* RETURN : INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
*
* DESCRIPTION : Detect if any GP events have occurred . This function is
* executed at interrupt level .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-08-05 12:44:28 +08:00
u32 acpi_ev_gpe_detect ( struct acpi_gpe_xrupt_info * gpe_xrupt_list )
2005-04-17 06:20:36 +08:00
{
2005-08-05 12:44:28 +08:00
u32 int_status = ACPI_INTERRUPT_NOT_HANDLED ;
u8 enabled_status_byte ;
struct acpi_gpe_register_info * gpe_register_info ;
u32 status_reg ;
u32 enable_reg ;
u32 flags ;
acpi_status status ;
struct acpi_gpe_block_info * gpe_block ;
acpi_native_uint i ;
acpi_native_uint j ;
ACPI_FUNCTION_NAME ( " ev_gpe_detect " ) ;
2005-04-17 06:20:36 +08:00
/* Check for the case where there are no GPEs */
if ( ! gpe_xrupt_list ) {
return ( int_status ) ;
}
/* Examine all GPE blocks attached to this interrupt level */
2005-08-05 12:44:28 +08:00
flags = acpi_os_acquire_lock ( acpi_gbl_gpe_lock ) ;
2005-04-17 06:20:36 +08:00
gpe_block = gpe_xrupt_list - > gpe_block_list_head ;
while ( gpe_block ) {
/*
* Read all of the 8 - bit GPE status and enable registers
* in this GPE block , saving all of them .
* Find all currently active GP events .
*/
for ( i = 0 ; i < gpe_block - > register_count ; i + + ) {
/* Get the next status/enable pair */
gpe_register_info = & gpe_block - > register_info [ i ] ;
/* Read the Status Register */
2005-08-05 12:44:28 +08:00
status =
acpi_hw_low_level_read ( ACPI_GPE_REGISTER_WIDTH ,
& status_reg ,
& gpe_register_info - >
status_address ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 06:20:36 +08:00
goto unlock_and_exit ;
}
/* Read the Enable Register */
2005-08-05 12:44:28 +08:00
status =
acpi_hw_low_level_read ( ACPI_GPE_REGISTER_WIDTH ,
& enable_reg ,
& gpe_register_info - >
enable_address ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 06:20:36 +08:00
goto unlock_and_exit ;
}
2005-08-05 12:44:28 +08:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INTERRUPTS ,
" Read GPE Register at GPE%X: Status=%02X, Enable=%02X \n " ,
gpe_register_info - > base_gpe_number ,
status_reg , enable_reg ) ) ;
2005-04-17 06:20:36 +08:00
2005-04-19 10:49:35 +08:00
/* Check if there is anything active at all in this register */
2005-04-17 06:20:36 +08:00
enabled_status_byte = ( u8 ) ( status_reg & enable_reg ) ;
if ( ! enabled_status_byte ) {
/* No active GPEs in this register, move on */
continue ;
}
/* Now look at the individual GPEs in this byte register */
for ( j = 0 ; j < ACPI_GPE_REGISTER_WIDTH ; j + + ) {
/* Examine one GPE bit */
2005-08-05 12:44:28 +08:00
if ( enabled_status_byte &
acpi_gbl_decode_to8bit [ j ] ) {
2005-04-17 06:20:36 +08:00
/*
* Found an active GPE . Dispatch the event to a handler
* or method .
*/
2005-08-05 12:44:28 +08:00
int_status | =
acpi_ev_gpe_dispatch ( & gpe_block - >
event_info [ ( i *
ACPI_GPE_REGISTER_WIDTH )
+
j ] ,
( u32 ) j +
gpe_register_info - >
base_gpe_number ) ;
2005-04-17 06:20:36 +08:00
}
}
}
gpe_block = gpe_block - > next ;
}
2005-08-05 12:44:28 +08:00
unlock_and_exit :
2005-04-17 06:20:36 +08:00
2005-08-05 12:44:28 +08:00
acpi_os_release_lock ( acpi_gbl_gpe_lock , flags ) ;
2005-04-17 06:20:36 +08:00
return ( int_status ) ;
}
/*******************************************************************************
*
* FUNCTION : acpi_ev_asynch_execute_gpe_method
*
* PARAMETERS : Context ( gpe_event_info ) - Info for this GPE
*
* RETURN : None
*
* DESCRIPTION : Perform the actual execution of a GPE control method . This
* function is called from an invocation of acpi_os_queue_for_execution
* ( and therefore does NOT execute at interrupt level ) so that
* the control method itself is not executed in the context of
* an interrupt handler .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-08-05 12:44:28 +08:00
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method ( void * context )
2005-04-17 06:20:36 +08:00
{
2005-08-05 12:44:28 +08:00
struct acpi_gpe_event_info * gpe_event_info = ( void * ) context ;
u32 gpe_number = 0 ;
acpi_status status ;
struct acpi_gpe_event_info local_gpe_event_info ;
struct acpi_parameter_info info ;
2005-04-17 06:20:36 +08:00
2005-08-05 12:44:28 +08:00
ACPI_FUNCTION_TRACE ( " ev_asynch_execute_gpe_method " ) ;
2005-04-17 06:20:36 +08:00
2005-08-05 12:44:28 +08:00
status = acpi_ut_acquire_mutex ( ACPI_MTX_EVENTS ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 06:20:36 +08:00
return_VOID ;
}
/* Must revalidate the gpe_number/gpe_block */
2005-08-05 12:44:28 +08:00
if ( ! acpi_ev_valid_gpe_event ( gpe_event_info ) ) {
status = acpi_ut_release_mutex ( ACPI_MTX_EVENTS ) ;
2005-04-17 06:20:36 +08:00
return_VOID ;
}
/* Set the GPE flags for return to enabled state */
2005-08-05 12:44:28 +08:00
( void ) acpi_ev_enable_gpe ( gpe_event_info , FALSE ) ;
2005-04-17 06:20:36 +08:00
/*
* Take a snapshot of the GPE info for this level - we copy the
* info to prevent a race condition with remove_handler / remove_block .
*/
2005-08-05 12:44:28 +08:00
ACPI_MEMCPY ( & local_gpe_event_info , gpe_event_info ,
sizeof ( struct acpi_gpe_event_info ) ) ;
2005-04-17 06:20:36 +08:00
2005-08-05 12:44:28 +08:00
status = acpi_ut_release_mutex ( ACPI_MTX_EVENTS ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 06:20:36 +08:00
return_VOID ;
}
/*
* Must check for control method type dispatch one more
* time to avoid race with ev_gpe_install_handler
*/
2005-04-19 10:49:35 +08:00
if ( ( local_gpe_event_info . flags & ACPI_GPE_DISPATCH_MASK ) = =
2005-08-05 12:44:28 +08:00
ACPI_GPE_DISPATCH_METHOD ) {
2005-04-17 06:20:36 +08:00
/*
* Invoke the GPE Method ( _Lxx , _Exx ) i . e . , evaluate the _Lxx / _Exx
* control method that corresponds to this GPE
*/
info . node = local_gpe_event_info . dispatch . method_node ;
2005-08-05 12:44:28 +08:00
info . parameters =
ACPI_CAST_PTR ( union acpi_operand_object * , gpe_event_info ) ;
2005-04-17 06:20:36 +08:00
info . parameter_type = ACPI_PARAM_GPE ;
2005-08-05 12:44:28 +08:00
status = acpi_ns_evaluate_by_handle ( & info ) ;
if ( ACPI_FAILURE ( status ) ) {
ACPI_REPORT_ERROR ( ( " %s while evaluating method [%4.4s] for GPE[%2X] \n " , acpi_format_exception ( status ) , acpi_ut_get_node_name ( local_gpe_event_info . dispatch . method_node ) , gpe_number ) ) ;
2005-04-17 06:20:36 +08:00
}
}
2005-04-19 10:49:35 +08:00
if ( ( local_gpe_event_info . flags & ACPI_GPE_XRUPT_TYPE_MASK ) = =
2005-08-05 12:44:28 +08:00
ACPI_GPE_LEVEL_TRIGGERED ) {
2005-04-17 06:20:36 +08:00
/*
* GPE is level - triggered , we clear the GPE status bit after
* handling the event .
*/
2005-08-05 12:44:28 +08:00
status = acpi_hw_clear_gpe ( & local_gpe_event_info ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 06:20:36 +08:00
return_VOID ;
}
}
/* Enable this GPE */
2005-08-05 12:44:28 +08:00
( void ) acpi_hw_write_gpe_enable_reg ( & local_gpe_event_info ) ;
2005-04-17 06:20:36 +08:00
return_VOID ;
}
/*******************************************************************************
*
* FUNCTION : acpi_ev_gpe_dispatch
*
2005-04-19 10:49:35 +08:00
* PARAMETERS : gpe_event_info - Info for this GPE
2005-04-17 06:20:36 +08:00
* gpe_number - Number relative to the parent GPE block
*
* RETURN : INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
*
* DESCRIPTION : Dispatch a General Purpose Event to either a function ( e . g . EC )
* or method ( e . g . _Lxx / _Exx ) handler .
*
* This function executes at interrupt level .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
u32
2005-08-05 12:44:28 +08:00
acpi_ev_gpe_dispatch ( struct acpi_gpe_event_info * gpe_event_info , u32 gpe_number )
2005-04-17 06:20:36 +08:00
{
2005-08-05 12:44:28 +08:00
acpi_status status ;
2005-04-17 06:20:36 +08:00
2005-08-05 12:44:28 +08:00
ACPI_FUNCTION_TRACE ( " ev_gpe_dispatch " ) ;
2005-04-17 06:20:36 +08:00
/*
* If edge - triggered , clear the GPE status bit now . Note that
* level - triggered events are cleared after the GPE is serviced .
*/
2005-04-19 10:49:35 +08:00
if ( ( gpe_event_info - > flags & ACPI_GPE_XRUPT_TYPE_MASK ) = =
2005-08-05 12:44:28 +08:00
ACPI_GPE_EDGE_TRIGGERED ) {
status = acpi_hw_clear_gpe ( gpe_event_info ) ;
if ( ACPI_FAILURE ( status ) ) {
ACPI_REPORT_ERROR ( ( " acpi_ev_gpe_dispatch: %s, Unable to clear GPE[%2X] \n " , acpi_format_exception ( status ) , gpe_number ) ) ;
return_VALUE ( ACPI_INTERRUPT_NOT_HANDLED ) ;
2005-04-17 06:20:36 +08:00
}
}
/* Save current system state */
if ( acpi_gbl_system_awake_and_running ) {
2005-08-05 12:44:28 +08:00
ACPI_SET_BIT ( gpe_event_info - > flags , ACPI_GPE_SYSTEM_RUNNING ) ;
} else {
ACPI_CLEAR_BIT ( gpe_event_info - > flags , ACPI_GPE_SYSTEM_RUNNING ) ;
2005-04-17 06:20:36 +08:00
}
/*
* Dispatch the GPE to either an installed handler , or the control
* method associated with this GPE ( _Lxx or _Exx ) .
* If a handler exists , we invoke it and do not attempt to run the method .
* If there is neither a handler nor a method , we disable the level to
* prevent further events from coming in here .
*/
switch ( gpe_event_info - > flags & ACPI_GPE_DISPATCH_MASK ) {
case ACPI_GPE_DISPATCH_HANDLER :
/*
* Invoke the installed handler ( at interrupt level )
* Ignore return status for now . TBD : leave GPE disabled on error ?
*/
2005-08-05 12:44:28 +08:00
( void ) gpe_event_info - > dispatch . handler - > address ( gpe_event_info - >
dispatch .
handler - >
context ) ;
2005-04-17 06:20:36 +08:00
/* It is now safe to clear level-triggered events. */
2005-04-19 10:49:35 +08:00
if ( ( gpe_event_info - > flags & ACPI_GPE_XRUPT_TYPE_MASK ) = =
2005-08-05 12:44:28 +08:00
ACPI_GPE_LEVEL_TRIGGERED ) {
status = acpi_hw_clear_gpe ( gpe_event_info ) ;
if ( ACPI_FAILURE ( status ) ) {
ACPI_REPORT_ERROR ( ( " acpi_ev_gpe_dispatch: %s, Unable to clear GPE[%2X] \n " , acpi_format_exception ( status ) , gpe_number ) ) ;
return_VALUE ( ACPI_INTERRUPT_NOT_HANDLED ) ;
2005-04-17 06:20:36 +08:00
}
}
break ;
case ACPI_GPE_DISPATCH_METHOD :
/*
* Disable GPE , so it doesn ' t keep firing before the method has a
* chance to run .
*/
2005-08-05 12:44:28 +08:00
status = acpi_ev_disable_gpe ( gpe_event_info ) ;
if ( ACPI_FAILURE ( status ) ) {
ACPI_REPORT_ERROR ( ( " acpi_ev_gpe_dispatch: %s, Unable to disable GPE[%2X] \n " , acpi_format_exception ( status ) , gpe_number ) ) ;
return_VALUE ( ACPI_INTERRUPT_NOT_HANDLED ) ;
2005-04-17 06:20:36 +08:00
}
/*
* Execute the method associated with the GPE
* NOTE : Level - triggered GPEs are cleared after the method completes .
*/
2005-08-05 12:44:28 +08:00
status = acpi_os_queue_for_execution ( OSD_PRIORITY_GPE ,
acpi_ev_asynch_execute_gpe_method ,
gpe_event_info ) ;
if ( ACPI_FAILURE ( status ) ) {
ACPI_REPORT_ERROR ( ( " acpi_ev_gpe_dispatch: %s, Unable to queue handler for GPE[%2X] - event disabled \n " , acpi_format_exception ( status ) , gpe_number ) ) ;
2005-04-17 06:20:36 +08:00
}
break ;
default :
/* No handler or method to run! */
2005-08-05 12:44:28 +08:00
ACPI_REPORT_ERROR ( ( " acpi_ev_gpe_dispatch: No handler or method for GPE[%2X], disabling event \n " , gpe_number ) ) ;
2005-04-17 06:20:36 +08:00
/*
* Disable the GPE . The GPE will remain disabled until the ACPI
* Core Subsystem is restarted , or a handler is installed .
*/
2005-08-05 12:44:28 +08:00
status = acpi_ev_disable_gpe ( gpe_event_info ) ;
if ( ACPI_FAILURE ( status ) ) {
ACPI_REPORT_ERROR ( ( " acpi_ev_gpe_dispatch: %s, Unable to disable GPE[%2X] \n " , acpi_format_exception ( status ) , gpe_number ) ) ;
return_VALUE ( ACPI_INTERRUPT_NOT_HANDLED ) ;
2005-04-17 06:20:36 +08:00
}
break ;
}
2005-08-05 12:44:28 +08:00
return_VALUE ( ACPI_INTERRUPT_HANDLED ) ;
2005-04-17 06:20:36 +08:00
}
# ifdef ACPI_GPE_NOTIFY_CHECK
/*******************************************************************************
* TBD : NOT USED , PROTOTYPE ONLY AND WILL PROBABLY BE REMOVED
*
* FUNCTION : acpi_ev_check_for_wake_only_gpe
*
* PARAMETERS : gpe_event_info - info for this GPE
*
* RETURN : Status
*
* DESCRIPTION : Determine if a a GPE is " wake-only " .
*
* Called from Notify ( ) code in interpreter when a " device_wake "
* Notify comes in .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status
2005-08-05 12:44:28 +08:00
acpi_ev_check_for_wake_only_gpe ( struct acpi_gpe_event_info * gpe_event_info )
2005-04-17 06:20:36 +08:00
{
2005-08-05 12:44:28 +08:00
acpi_status status ;
2005-04-17 06:20:36 +08:00
2005-08-05 12:44:28 +08:00
ACPI_FUNCTION_TRACE ( " ev_check_for_wake_only_gpe " ) ;
2005-04-17 06:20:36 +08:00
2005-08-05 12:44:28 +08:00
if ( ( gpe_event_info ) & & /* Only >0 for _Lxx/_Exx */
( ( gpe_event_info - > flags & ACPI_GPE_SYSTEM_MASK ) = = ACPI_GPE_SYSTEM_RUNNING ) ) { /* System state at GPE time */
2005-04-17 06:20:36 +08:00
/* This must be a wake-only GPE, disable it */
2005-08-05 12:44:28 +08:00
status = acpi_ev_disable_gpe ( gpe_event_info ) ;
2005-04-17 06:20:36 +08:00
/* Set GPE to wake-only. Do not change wake disabled/enabled status */
2005-08-05 12:44:28 +08:00
acpi_ev_set_gpe_type ( gpe_event_info , ACPI_GPE_TYPE_WAKE ) ;
2005-04-17 06:20:36 +08:00
2005-08-05 12:44:28 +08:00
ACPI_REPORT_INFO ( ( " GPE %p was updated from wake/run to wake-only \n " , gpe_event_info ) ) ;
2005-04-17 06:20:36 +08:00
/* This was a wake-only GPE */
2005-08-05 12:44:28 +08:00
return_ACPI_STATUS ( AE_WAKE_ONLY_GPE ) ;
2005-04-17 06:20:36 +08:00
}
2005-08-05 12:44:28 +08:00
return_ACPI_STATUS ( AE_OK ) ;
2005-04-17 06:20:36 +08:00
}
# endif