2005-04-17 02:20:36 +04:00
/******************************************************************************
*
* Module Name : exconfig - Namespace reconfiguration ( Load / Unload opcodes )
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* 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/acinterp.h>
# include <acpi/amlcode.h>
# include <acpi/acnamesp.h>
# include <acpi/acevents.h>
# include <acpi/actables.h>
# include <acpi/acdispat.h>
# define _COMPONENT ACPI_EXECUTER
2005-08-05 08:44:28 +04:00
ACPI_MODULE_NAME ( " exconfig " )
2005-04-17 02:20:36 +04:00
2005-04-19 06:49:35 +04:00
/* Local prototypes */
static acpi_status
2005-08-05 08:44:28 +04:00
acpi_ex_add_table ( struct acpi_table_header * table ,
struct acpi_namespace_node * parent_node ,
union acpi_operand_object * * ddb_handle ) ;
2005-04-17 02:20:36 +04:00
/*******************************************************************************
*
* FUNCTION : acpi_ex_add_table
*
* PARAMETERS : Table - Pointer to raw table
* parent_node - Where to load the table ( scope )
* ddb_handle - Where to return the table handle .
*
* RETURN : Status
*
* DESCRIPTION : Common function to Install and Load an ACPI table with a
* returned table handle .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-04-19 06:49:35 +04:00
static acpi_status
2005-08-05 08:44:28 +04:00
acpi_ex_add_table ( struct acpi_table_header * table ,
struct acpi_namespace_node * parent_node ,
union acpi_operand_object * * ddb_handle )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status ;
struct acpi_table_desc table_info ;
union acpi_operand_object * obj_desc ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
ACPI_FUNCTION_TRACE ( " ex_add_table " ) ;
2005-04-17 02:20:36 +04:00
/* Create an object to be the table handle */
2005-08-05 08:44:28 +04:00
obj_desc = acpi_ut_create_internal_object ( ACPI_TYPE_LOCAL_REFERENCE ) ;
2005-04-17 02:20:36 +04:00
if ( ! obj_desc ) {
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( AE_NO_MEMORY ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-30 02:15:00 +04:00
/* Init the table handle */
obj_desc - > reference . opcode = AML_LOAD_OP ;
* ddb_handle = obj_desc ;
2005-04-17 02:20:36 +04:00
/* Install the new table into the local data structures */
2005-08-05 08:44:28 +04:00
ACPI_MEMSET ( & table_info , 0 , sizeof ( struct acpi_table_desc ) ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
table_info . type = ACPI_TABLE_SSDT ;
table_info . pointer = table ;
table_info . length = ( acpi_size ) table - > length ;
2005-04-19 06:49:35 +04:00
table_info . allocation = ACPI_MEM_ALLOCATED ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
status = acpi_tb_install_table ( & table_info ) ;
2005-07-30 02:15:00 +04:00
obj_desc - > reference . object = table_info . installed_desc ;
2005-08-05 08:44:28 +04:00
if ( ACPI_FAILURE ( status ) ) {
2005-07-30 02:15:00 +04:00
if ( status = = AE_ALREADY_EXISTS ) {
/* Table already exists, just return the handle */
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( AE_OK ) ;
2005-07-30 02:15:00 +04:00
}
2005-04-17 02:20:36 +04:00
goto cleanup ;
}
/* Add the table to the namespace */
2005-08-05 08:44:28 +04:00
status = acpi_ns_load_table ( table_info . installed_desc , parent_node ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 02:20:36 +04:00
/* Uninstall table on error */
2005-08-05 08:44:28 +04:00
( void ) acpi_tb_uninstall_table ( table_info . installed_desc ) ;
2005-04-17 02:20:36 +04:00
goto cleanup ;
}
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( AE_OK ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
cleanup :
acpi_ut_remove_reference ( obj_desc ) ;
2005-07-30 02:15:00 +04:00
* ddb_handle = NULL ;
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( status ) ;
2005-04-17 02:20:36 +04:00
}
/*******************************************************************************
*
* FUNCTION : acpi_ex_load_table_op
*
* PARAMETERS : walk_state - Current state with operands
* return_desc - Where to store the return object
*
* RETURN : Status
*
* DESCRIPTION : Load an ACPI table
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status
2005-08-05 08:44:28 +04:00
acpi_ex_load_table_op ( struct acpi_walk_state * walk_state ,
union acpi_operand_object * * return_desc )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status ;
union acpi_operand_object * * operand = & walk_state - > operands [ 0 ] ;
struct acpi_table_header * table ;
struct acpi_namespace_node * parent_node ;
struct acpi_namespace_node * start_node ;
struct acpi_namespace_node * parameter_node = NULL ;
union acpi_operand_object * ddb_handle ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
ACPI_FUNCTION_TRACE ( " ex_load_table_op " ) ;
2005-04-17 02:20:36 +04:00
#if 0
/*
* Make sure that the signature does not match one of the tables that
* is already loaded .
*/
2005-08-05 08:44:28 +04:00
status = acpi_tb_match_signature ( operand [ 0 ] - > string . pointer , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( status = = AE_OK ) {
/* Signature matched -- don't allow override */
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( AE_ALREADY_EXISTS ) ;
2005-04-17 02:20:36 +04:00
}
# endif
/* Find the ACPI table */
2005-08-05 08:44:28 +04:00
status = acpi_tb_find_table ( operand [ 0 ] - > string . pointer ,
operand [ 1 ] - > string . pointer ,
operand [ 2 ] - > string . pointer , & table ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 02:20:36 +04:00
if ( status ! = AE_NOT_FOUND ) {
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( status ) ;
2005-04-17 02:20:36 +04:00
}
/* Table not found, return an Integer=0 and AE_OK */
2005-08-05 08:44:28 +04:00
ddb_handle = acpi_ut_create_internal_object ( ACPI_TYPE_INTEGER ) ;
2005-04-17 02:20:36 +04:00
if ( ! ddb_handle ) {
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( AE_NO_MEMORY ) ;
2005-04-17 02:20:36 +04:00
}
ddb_handle - > integer . value = 0 ;
* return_desc = ddb_handle ;
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( AE_OK ) ;
2005-04-17 02:20:36 +04:00
}
/* Default nodes */
start_node = walk_state - > scope_info - > scope . node ;
parent_node = acpi_gbl_root_node ;
/* root_path (optional parameter) */
if ( operand [ 3 ] - > string . length > 0 ) {
/*
* Find the node referenced by the root_path_string . This is the
* location within the namespace where the table will be loaded .
*/
2005-08-05 08:44:28 +04:00
status =
acpi_ns_get_node_by_path ( operand [ 3 ] - > string . pointer ,
start_node , ACPI_NS_SEARCH_PARENT ,
& parent_node ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-17 02:20:36 +04:00
}
}
/* parameter_path (optional parameter) */
if ( operand [ 4 ] - > string . length > 0 ) {
if ( ( operand [ 4 ] - > string . pointer [ 0 ] ! = ' \\ ' ) & &
2005-08-05 08:44:28 +04:00
( operand [ 4 ] - > string . pointer [ 0 ] ! = ' ^ ' ) ) {
2005-04-17 02:20:36 +04:00
/*
* Path is not absolute , so it will be relative to the node
* referenced by the root_path_string ( or the NS root if omitted )
*/
start_node = parent_node ;
}
2005-04-19 06:49:35 +04:00
/* Find the node referenced by the parameter_path_string */
2005-08-05 08:44:28 +04:00
status =
acpi_ns_get_node_by_path ( operand [ 4 ] - > string . pointer ,
start_node , ACPI_NS_SEARCH_PARENT ,
& parameter_node ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-17 02:20:36 +04:00
}
}
/* Load the table into the namespace */
2005-08-05 08:44:28 +04:00
status = acpi_ex_add_table ( table , parent_node , & ddb_handle ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-17 02:20:36 +04:00
}
/* Parameter Data (optional) */
if ( parameter_node ) {
/* Store the parameter data into the optional parameter object */
2005-08-05 08:44:28 +04:00
status = acpi_ex_store ( operand [ 5 ] ,
ACPI_CAST_PTR ( union acpi_operand_object ,
parameter_node ) ,
walk_state ) ;
if ( ACPI_FAILURE ( status ) ) {
( void ) acpi_ex_unload_table ( ddb_handle ) ;
return_ACPI_STATUS ( status ) ;
2005-04-17 02:20:36 +04:00
}
}
* return_desc = ddb_handle ;
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( status ) ;
2005-04-17 02:20:36 +04:00
}
/*******************************************************************************
*
* FUNCTION : acpi_ex_load_op
*
* PARAMETERS : obj_desc - Region or Field where the table will be
* obtained
* Target - Where a handle to the table will be stored
* walk_state - Current state
*
* RETURN : Status
*
* DESCRIPTION : Load an ACPI table from a field or operation region
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status
2005-08-05 08:44:28 +04:00
acpi_ex_load_op ( union acpi_operand_object * obj_desc ,
union acpi_operand_object * target ,
struct acpi_walk_state * walk_state )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status ;
union acpi_operand_object * ddb_handle ;
union acpi_operand_object * buffer_desc = NULL ;
struct acpi_table_header * table_ptr = NULL ;
acpi_physical_address address ;
struct acpi_table_header table_header ;
u32 i ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
ACPI_FUNCTION_TRACE ( " ex_load_op " ) ;
2005-04-17 02:20:36 +04:00
/* Object can be either an op_region or a Field */
2005-08-05 08:44:28 +04:00
switch ( ACPI_GET_OBJECT_TYPE ( obj_desc ) ) {
2005-04-17 02:20:36 +04:00
case ACPI_TYPE_REGION :
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_EXEC , " Load from Region %p %s \n " ,
obj_desc ,
acpi_ut_get_object_type_name ( obj_desc ) ) ) ;
2005-04-17 02:20:36 +04:00
/*
* If the Region Address and Length have not been previously evaluated ,
* evaluate them now and save the results .
*/
if ( ! ( obj_desc - > common . flags & AOPOBJ_DATA_VALID ) ) {
2005-08-05 08:44:28 +04:00
status = acpi_ds_get_region_arguments ( obj_desc ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-17 02:20:36 +04:00
}
}
/* Get the base physical address of the region */
address = obj_desc - > region . address ;
/* Get the table length from the table header */
table_header . length = 0 ;
for ( i = 0 ; i < 8 ; i + + ) {
2005-08-05 08:44:28 +04:00
status =
acpi_ev_address_space_dispatch ( obj_desc , ACPI_READ ,
( acpi_physical_address )
( i + address ) , 8 ,
( ( u8 * ) &
table_header ) + i ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-17 02:20:36 +04:00
}
}
/* Sanity check the table length */
2005-08-05 08:44:28 +04:00
if ( table_header . length < sizeof ( struct acpi_table_header ) ) {
return_ACPI_STATUS ( AE_BAD_HEADER ) ;
2005-04-17 02:20:36 +04:00
}
/* Allocate a buffer for the entire table */
2005-08-05 08:44:28 +04:00
table_ptr = ACPI_MEM_ALLOCATE ( table_header . length ) ;
2005-04-17 02:20:36 +04:00
if ( ! table_ptr ) {
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( AE_NO_MEMORY ) ;
2005-04-17 02:20:36 +04:00
}
/* Get the entire table from the op region */
for ( i = 0 ; i < table_header . length ; i + + ) {
2005-08-05 08:44:28 +04:00
status =
acpi_ev_address_space_dispatch ( obj_desc , ACPI_READ ,
( acpi_physical_address )
( i + address ) , 8 ,
( ( u8 * ) table_ptr +
i ) ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 02:20:36 +04:00
goto cleanup ;
}
}
break ;
case ACPI_TYPE_LOCAL_REGION_FIELD :
case ACPI_TYPE_LOCAL_BANK_FIELD :
case ACPI_TYPE_LOCAL_INDEX_FIELD :
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_EXEC , " Load from Field %p %s \n " ,
obj_desc ,
acpi_ut_get_object_type_name ( obj_desc ) ) ) ;
2005-04-17 02:20:36 +04:00
/*
* The length of the field must be at least as large as the table .
* Read the entire field and thus the entire table . Buffer is
* allocated during the read .
*/
2005-08-05 08:44:28 +04:00
status =
acpi_ex_read_data_from_field ( walk_state , obj_desc ,
& buffer_desc ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
table_ptr = ACPI_CAST_PTR ( struct acpi_table_header ,
buffer_desc - > buffer . pointer ) ;
2005-04-17 02:20:36 +04:00
2005-05-26 08:00:00 +04:00
/* All done with the buffer_desc, delete it */
buffer_desc - > buffer . pointer = NULL ;
2005-08-05 08:44:28 +04:00
acpi_ut_remove_reference ( buffer_desc ) ;
2005-05-26 08:00:00 +04:00
/* Sanity check the table length */
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
if ( table_ptr - > length < sizeof ( struct acpi_table_header ) ) {
2005-05-26 08:00:00 +04:00
status = AE_BAD_HEADER ;
goto cleanup ;
2005-04-17 02:20:36 +04:00
}
break ;
default :
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( AE_AML_OPERAND_TYPE ) ;
2005-04-17 02:20:36 +04:00
}
/* The table must be either an SSDT or a PSDT */
2005-08-05 08:44:28 +04:00
if ( ( ! ACPI_STRNCMP ( table_ptr - > signature ,
acpi_gbl_table_data [ ACPI_TABLE_PSDT ] . signature ,
acpi_gbl_table_data [ ACPI_TABLE_PSDT ] . sig_length ) ) & &
( ! ACPI_STRNCMP ( table_ptr - > signature ,
acpi_gbl_table_data [ ACPI_TABLE_SSDT ] . signature ,
acpi_gbl_table_data [ ACPI_TABLE_SSDT ] . sig_length ) ) ) {
ACPI_DEBUG_PRINT ( ( ACPI_DB_ERROR ,
" Table has invalid signature [%4.4s], must be SSDT or PSDT \n " ,
table_ptr - > signature ) ) ;
2005-04-17 02:20:36 +04:00
status = AE_BAD_SIGNATURE ;
goto cleanup ;
}
/* Install the new table into the local data structures */
2005-08-05 08:44:28 +04:00
status = acpi_ex_add_table ( table_ptr , acpi_gbl_root_node , & ddb_handle ) ;
if ( ACPI_FAILURE ( status ) ) {
2005-05-26 08:00:00 +04:00
/* On error, table_ptr was deallocated above */
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( status ) ;
2005-04-17 02:20:36 +04:00
}
/* Store the ddb_handle into the Target operand */
2005-08-05 08:44:28 +04:00
status = acpi_ex_store ( ddb_handle , target , walk_state ) ;
if ( ACPI_FAILURE ( status ) ) {
( void ) acpi_ex_unload_table ( ddb_handle ) ;
2005-04-17 02:20:36 +04:00
2005-05-26 08:00:00 +04:00
/* table_ptr was deallocated above */
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( status ) ;
2005-05-26 08:00:00 +04:00
}
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
cleanup :
if ( ACPI_FAILURE ( status ) ) {
ACPI_MEM_FREE ( table_ptr ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( status ) ;
2005-04-17 02:20:36 +04:00
}
/*******************************************************************************
*
* FUNCTION : acpi_ex_unload_table
*
* PARAMETERS : ddb_handle - Handle to a previously loaded table
*
* RETURN : Status
*
* DESCRIPTION : Unload an ACPI table
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-08-05 08:44:28 +04:00
acpi_status acpi_ex_unload_table ( union acpi_operand_object * ddb_handle )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = AE_OK ;
union acpi_operand_object * table_desc = ddb_handle ;
struct acpi_table_desc * table_info ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
ACPI_FUNCTION_TRACE ( " ex_unload_table " ) ;
2005-04-17 02:20:36 +04:00
/*
* Validate the handle
* Although the handle is partially validated in acpi_ex_reconfiguration ( ) ,
* when it calls acpi_ex_resolve_operands ( ) , the handle is more completely
* validated here .
*/
if ( ( ! ddb_handle ) | |
2005-08-05 08:44:28 +04:00
( ACPI_GET_DESCRIPTOR_TYPE ( ddb_handle ) ! = ACPI_DESC_TYPE_OPERAND ) | |
( ACPI_GET_OBJECT_TYPE ( ddb_handle ) ! = ACPI_TYPE_LOCAL_REFERENCE ) ) {
return_ACPI_STATUS ( AE_BAD_PARAMETER ) ;
2005-04-17 02:20:36 +04:00
}
/* Get the actual table descriptor from the ddb_handle */
2005-08-05 08:44:28 +04:00
table_info = ( struct acpi_table_desc * ) table_desc - > reference . object ;
2005-04-17 02:20:36 +04:00
/*
* Delete the entire namespace under this table Node
* ( Offset contains the table_id )
*/
2005-08-05 08:44:28 +04:00
acpi_ns_delete_namespace_by_owner ( table_info - > owner_id ) ;
acpi_ut_release_owner_id ( & table_info - > owner_id ) ;
2005-04-17 02:20:36 +04:00
/* Delete the table itself */
2005-08-05 08:44:28 +04:00
( void ) acpi_tb_uninstall_table ( table_info - > installed_desc ) ;
2005-04-17 02:20:36 +04:00
/* Delete the table descriptor (ddb_handle) */
2005-08-05 08:44:28 +04:00
acpi_ut_remove_reference ( table_desc ) ;
return_ACPI_STATUS ( status ) ;
2005-04-17 02:20:36 +04:00
}