2005-04-17 02:20:36 +04:00
/******************************************************************************
*
* Module Name : exmisc - ACPI AML ( p - code ) execution - specific opcodes
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
2006-01-14 00:22:00 +03:00
* Copyright ( C ) 2000 - 2006 , R . Byron Moore
2005-04-17 02:20:36 +04:00
* 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>
2005-11-02 08:00:00 +03:00
# include <acpi/amlresrc.h>
2005-04-17 02:20:36 +04:00
# define _COMPONENT ACPI_EXECUTER
2005-08-05 08:44:28 +04:00
ACPI_MODULE_NAME ( " exmisc " )
2005-04-17 02:20:36 +04:00
/*******************************************************************************
*
* FUNCTION : acpi_ex_get_object_reference
*
* PARAMETERS : obj_desc - Create a reference to this object
* return_desc - Where to store the reference
* walk_state - Current state
*
* RETURN : Status
*
* DESCRIPTION : Obtain and return a " reference " to the target object
* Common code for the ref_of_op and the cond_ref_of_op .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status
2005-08-05 08:44:28 +04:00
acpi_ex_get_object_reference ( union acpi_operand_object * obj_desc ,
union acpi_operand_object * * return_desc ,
struct acpi_walk_state * walk_state )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
union acpi_operand_object * reference_obj ;
union acpi_operand_object * referenced_obj ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
ACPI_FUNCTION_TRACE_PTR ( " ex_get_object_reference " , obj_desc ) ;
2005-04-17 02:20:36 +04:00
* return_desc = NULL ;
2005-08-05 08:44:28 +04:00
switch ( ACPI_GET_DESCRIPTOR_TYPE ( obj_desc ) ) {
2005-04-17 02:20:36 +04:00
case ACPI_DESC_TYPE_OPERAND :
2005-08-05 08:44:28 +04:00
if ( ACPI_GET_OBJECT_TYPE ( obj_desc ) ! = ACPI_TYPE_LOCAL_REFERENCE ) {
return_ACPI_STATUS ( AE_AML_OPERAND_TYPE ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Must be a reference to a Local or Arg
*/
switch ( obj_desc - > reference . opcode ) {
case AML_LOCAL_OP :
case AML_ARG_OP :
case AML_DEBUG_OP :
/* The referenced object is the pseudo-node for the local/arg */
referenced_obj = obj_desc - > reference . object ;
break ;
default :
2006-01-28 00:43:00 +03:00
ACPI_ERROR ( ( AE_INFO , " Unknown Reference opcode %X " ,
obj_desc - > reference . opcode ) ) ;
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( AE_AML_INTERNAL ) ;
2005-04-17 02:20:36 +04:00
}
break ;
case ACPI_DESC_TYPE_NAMED :
/*
* A named reference that has already been resolved to a Node
*/
referenced_obj = obj_desc ;
break ;
default :
2006-01-28 00:43:00 +03:00
ACPI_ERROR ( ( AE_INFO , " Invalid descriptor type %X " ,
ACPI_GET_DESCRIPTOR_TYPE ( obj_desc ) ) ) ;
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( AE_TYPE ) ;
2005-04-17 02:20:36 +04:00
}
/* Create a new reference object */
2005-08-05 08:44:28 +04:00
reference_obj =
acpi_ut_create_internal_object ( ACPI_TYPE_LOCAL_REFERENCE ) ;
2005-04-17 02:20:36 +04:00
if ( ! reference_obj ) {
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( AE_NO_MEMORY ) ;
2005-04-17 02:20:36 +04:00
}
reference_obj - > reference . opcode = AML_REF_OF_OP ;
reference_obj - > reference . object = referenced_obj ;
* return_desc = reference_obj ;
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_EXEC ,
" Object %p Type [%s], returning Reference %p \n " ,
obj_desc , acpi_ut_get_object_type_name ( obj_desc ) ,
* return_desc ) ) ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( AE_OK ) ;
2005-04-17 02:20:36 +04:00
}
/*******************************************************************************
*
* FUNCTION : acpi_ex_concat_template
*
* PARAMETERS : Operand0 - First source object
* Operand1 - Second source object
* actual_return_desc - Where to place the return object
* walk_state - Current walk state
*
* RETURN : Status
*
* DESCRIPTION : Concatenate two resource templates
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status
2005-08-05 08:44:28 +04:00
acpi_ex_concat_template ( union acpi_operand_object * operand0 ,
union acpi_operand_object * operand1 ,
union acpi_operand_object * * actual_return_desc ,
struct acpi_walk_state * walk_state )
2005-04-17 02:20:36 +04:00
{
2005-11-02 08:00:00 +03:00
acpi_status status ;
2005-08-05 08:44:28 +04:00
union acpi_operand_object * return_desc ;
u8 * new_buf ;
2005-11-02 08:00:00 +03:00
u8 * end_tag ;
acpi_size length0 ;
2005-08-05 08:44:28 +04:00
acpi_size length1 ;
2006-01-28 00:43:00 +03:00
acpi_size new_length ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
ACPI_FUNCTION_TRACE ( " ex_concat_template " ) ;
2005-04-17 02:20:36 +04:00
2005-11-02 08:00:00 +03:00
/*
* Find the end_tag descriptor in each resource template .
2006-01-28 00:43:00 +03:00
* Note1 : returned pointers point TO the end_tag , not past it .
* Note2 : zero - length buffers are allowed ; treated like one end_tag
2005-11-02 08:00:00 +03:00
*/
2006-01-28 00:43:00 +03:00
/* Get the length of the first resource template */
2005-11-02 08:00:00 +03:00
status = acpi_ut_get_resource_end_tag ( operand0 , & end_tag ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
}
length0 = ACPI_PTR_DIFF ( end_tag , operand0 - > buffer . pointer ) ;
2005-04-17 02:20:36 +04:00
2006-01-28 00:43:00 +03:00
/* Get the length of the second resource template */
2005-11-02 08:00:00 +03:00
status = acpi_ut_get_resource_end_tag ( operand1 , & end_tag ) ;
if ( ACPI_FAILURE ( status ) ) {
return_ACPI_STATUS ( status ) ;
2005-04-17 02:20:36 +04:00
}
2006-01-28 00:43:00 +03:00
length1 = ACPI_PTR_DIFF ( end_tag , operand1 - > buffer . pointer ) ;
/* Combine both lengths, minimum size will be 2 for end_tag */
2005-04-17 02:20:36 +04:00
2006-01-28 00:43:00 +03:00
new_length = length0 + length1 + sizeof ( struct aml_resource_end_tag ) ;
2005-04-17 02:20:36 +04:00
2006-01-28 00:43:00 +03:00
/* Create a new buffer object for the result (with one end_tag) */
2005-04-17 02:20:36 +04:00
2006-01-28 00:43:00 +03:00
return_desc = acpi_ut_create_buffer_object ( new_length ) ;
2005-04-17 02:20:36 +04:00
if ( ! return_desc ) {
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( AE_NO_MEMORY ) ;
2005-04-17 02:20:36 +04:00
}
2005-11-02 08:00:00 +03:00
/*
* Copy the templates to the new buffer , 0 first , then 1 follows . One
* end_tag descriptor is copied from Operand1 .
*/
2005-04-17 02:20:36 +04:00
new_buf = return_desc - > buffer . pointer ;
2005-11-02 08:00:00 +03:00
ACPI_MEMCPY ( new_buf , operand0 - > buffer . pointer , length0 ) ;
ACPI_MEMCPY ( new_buf + length0 , operand1 - > buffer . pointer , length1 ) ;
2005-04-17 02:20:36 +04:00
2006-01-28 00:43:00 +03:00
/* Insert end_tag and set the checksum to zero, means "ignore checksum" */
2005-04-17 02:20:36 +04:00
2006-01-28 00:43:00 +03:00
new_buf [ new_length - 1 ] = 0 ;
new_buf [ new_length - 2 ] = ACPI_RESOURCE_NAME_END_TAG | 1 ;
2005-04-17 02:20:36 +04:00
2005-11-02 08:00:00 +03:00
/* Return the completed resource template */
2005-04-17 02:20:36 +04:00
* actual_return_desc = return_desc ;
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( AE_OK ) ;
2005-04-17 02:20:36 +04:00
}
/*******************************************************************************
*
* FUNCTION : acpi_ex_do_concatenate
*
* PARAMETERS : Operand0 - First source object
* Operand1 - Second source object
* actual_return_desc - Where to place the return object
* walk_state - Current walk state
*
* RETURN : Status
*
* DESCRIPTION : Concatenate two objects OF THE SAME TYPE .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status
2005-08-05 08:44:28 +04:00
acpi_ex_do_concatenate ( union acpi_operand_object * operand0 ,
union acpi_operand_object * operand1 ,
union acpi_operand_object * * actual_return_desc ,
struct acpi_walk_state * walk_state )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
union acpi_operand_object * local_operand1 = operand1 ;
union acpi_operand_object * return_desc ;
char * new_buf ;
acpi_status status ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
ACPI_FUNCTION_TRACE ( " ex_do_concatenate " ) ;
2005-04-17 02:20:36 +04:00
/*
* Convert the second operand if necessary . The first operand
* determines the type of the second operand , ( See the Data Types
* section of the ACPI specification . ) Both object types are
* guaranteed to be either Integer / String / Buffer by the operand
* resolution mechanism .
*/
2005-08-05 08:44:28 +04:00
switch ( ACPI_GET_OBJECT_TYPE ( operand0 ) ) {
2005-04-17 02:20:36 +04:00
case ACPI_TYPE_INTEGER :
2005-08-05 08:44:28 +04:00
status =
acpi_ex_convert_to_integer ( operand1 , & local_operand1 , 16 ) ;
2005-04-17 02:20:36 +04:00
break ;
case ACPI_TYPE_STRING :
2005-08-05 08:44:28 +04:00
status = acpi_ex_convert_to_string ( operand1 , & local_operand1 ,
ACPI_IMPLICIT_CONVERT_HEX ) ;
2005-04-17 02:20:36 +04:00
break ;
case ACPI_TYPE_BUFFER :
2005-08-05 08:44:28 +04:00
status = acpi_ex_convert_to_buffer ( operand1 , & local_operand1 ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
2006-01-28 00:43:00 +03:00
ACPI_ERROR ( ( AE_INFO , " Invalid object type: %X " ,
ACPI_GET_OBJECT_TYPE ( operand0 ) ) ) ;
2005-04-17 02:20:36 +04:00
status = AE_AML_INTERNAL ;
}
2005-08-05 08:44:28 +04:00
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 02:20:36 +04:00
goto cleanup ;
}
/*
* Both operands are now known to be the same object type
* ( Both are Integer , String , or Buffer ) , and we can now perform the
* concatenation .
*/
/*
* There are three cases to handle :
*
* 1 ) Two Integers concatenated to produce a new Buffer
* 2 ) Two Strings concatenated to produce a new String
* 3 ) Two Buffers concatenated to produce a new Buffer
*/
2005-08-05 08:44:28 +04:00
switch ( ACPI_GET_OBJECT_TYPE ( operand0 ) ) {
2005-04-17 02:20:36 +04:00
case ACPI_TYPE_INTEGER :
/* Result of two Integers is a Buffer */
/* Need enough buffer space for two integers */
2005-08-05 08:44:28 +04:00
return_desc = acpi_ut_create_buffer_object ( ( acpi_size )
ACPI_MUL_2
( acpi_gbl_integer_byte_width ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! return_desc ) {
status = AE_NO_MEMORY ;
goto cleanup ;
}
2005-08-05 08:44:28 +04:00
new_buf = ( char * ) return_desc - > buffer . pointer ;
2005-04-17 02:20:36 +04:00
/* Copy the first integer, LSB first */
2005-11-17 21:07:00 +03:00
ACPI_MEMCPY ( new_buf , & operand0 - > integer . value ,
2005-08-05 08:44:28 +04:00
acpi_gbl_integer_byte_width ) ;
2005-04-17 02:20:36 +04:00
/* Copy the second integer (LSB first) after the first */
2005-08-05 08:44:28 +04:00
ACPI_MEMCPY ( new_buf + acpi_gbl_integer_byte_width ,
& local_operand1 - > integer . value ,
acpi_gbl_integer_byte_width ) ;
2005-04-17 02:20:36 +04:00
break ;
case ACPI_TYPE_STRING :
/* Result of two Strings is a String */
2005-11-17 21:07:00 +03:00
return_desc = acpi_ut_create_string_object ( ( acpi_size )
( operand0 - > string .
length +
local_operand1 - >
string . length ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! return_desc ) {
status = AE_NO_MEMORY ;
goto cleanup ;
}
new_buf = return_desc - > string . pointer ;
/* Concatenate the strings */
2005-08-05 08:44:28 +04:00
ACPI_STRCPY ( new_buf , operand0 - > string . pointer ) ;
ACPI_STRCPY ( new_buf + operand0 - > string . length ,
local_operand1 - > string . pointer ) ;
2005-04-17 02:20:36 +04:00
break ;
case ACPI_TYPE_BUFFER :
/* Result of two Buffers is a Buffer */
2005-08-05 08:44:28 +04:00
return_desc = acpi_ut_create_buffer_object ( ( acpi_size )
2005-11-17 21:07:00 +03:00
( operand0 - > buffer .
length +
local_operand1 - >
buffer . length ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! return_desc ) {
status = AE_NO_MEMORY ;
goto cleanup ;
}
2005-08-05 08:44:28 +04:00
new_buf = ( char * ) return_desc - > buffer . pointer ;
2005-04-17 02:20:36 +04:00
/* Concatenate the buffers */
2005-11-17 21:07:00 +03:00
ACPI_MEMCPY ( new_buf , operand0 - > buffer . pointer ,
operand0 - > buffer . length ) ;
2005-08-05 08:44:28 +04:00
ACPI_MEMCPY ( new_buf + operand0 - > buffer . length ,
local_operand1 - > buffer . pointer ,
local_operand1 - > buffer . length ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
/* Invalid object type, should not happen here */
2006-01-28 00:43:00 +03:00
ACPI_ERROR ( ( AE_INFO , " Invalid object type: %X " ,
ACPI_GET_OBJECT_TYPE ( operand0 ) ) ) ;
2005-08-05 08:44:28 +04:00
status = AE_AML_INTERNAL ;
2005-04-17 02:20:36 +04:00
goto cleanup ;
}
* actual_return_desc = return_desc ;
2005-08-05 08:44:28 +04:00
cleanup :
2005-04-17 02:20:36 +04:00
if ( local_operand1 ! = operand1 ) {
2005-08-05 08:44:28 +04:00
acpi_ut_remove_reference ( local_operand1 ) ;
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_do_math_op
*
* PARAMETERS : Opcode - AML opcode
* Integer0 - Integer operand # 0
* Integer1 - Integer operand # 1
*
* RETURN : Integer result of the operation
*
* DESCRIPTION : Execute a math AML opcode . The purpose of having all of the
* math functions here is to prevent a lot of pointer dereferencing
* to obtain the operands .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_integer
2005-08-05 08:44:28 +04:00
acpi_ex_do_math_op ( u16 opcode , acpi_integer integer0 , acpi_integer integer1 )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
ACPI_FUNCTION_ENTRY ( ) ;
2005-04-17 02:20:36 +04:00
switch ( opcode ) {
2005-08-05 08:44:28 +04:00
case AML_ADD_OP : /* Add (Integer0, Integer1, Result) */
2005-04-17 02:20:36 +04:00
return ( integer0 + integer1 ) ;
2005-08-05 08:44:28 +04:00
case AML_BIT_AND_OP : /* And (Integer0, Integer1, Result) */
2005-04-17 02:20:36 +04:00
return ( integer0 & integer1 ) ;
2005-08-05 08:44:28 +04:00
case AML_BIT_NAND_OP : /* NAnd (Integer0, Integer1, Result) */
2005-04-17 02:20:36 +04:00
return ( ~ ( integer0 & integer1 ) ) ;
2005-08-05 08:44:28 +04:00
case AML_BIT_OR_OP : /* Or (Integer0, Integer1, Result) */
2005-04-17 02:20:36 +04:00
return ( integer0 | integer1 ) ;
2005-08-05 08:44:28 +04:00
case AML_BIT_NOR_OP : /* NOr (Integer0, Integer1, Result) */
2005-04-17 02:20:36 +04:00
return ( ~ ( integer0 | integer1 ) ) ;
2005-08-05 08:44:28 +04:00
case AML_BIT_XOR_OP : /* XOr (Integer0, Integer1, Result) */
2005-04-17 02:20:36 +04:00
return ( integer0 ^ integer1 ) ;
2005-08-05 08:44:28 +04:00
case AML_MULTIPLY_OP : /* Multiply (Integer0, Integer1, Result) */
2005-04-17 02:20:36 +04:00
return ( integer0 * integer1 ) ;
2005-08-05 08:44:28 +04:00
case AML_SHIFT_LEFT_OP : /* shift_left (Operand, shift_count, Result) */
2005-04-17 02:20:36 +04:00
return ( integer0 < < integer1 ) ;
2005-08-05 08:44:28 +04:00
case AML_SHIFT_RIGHT_OP : /* shift_right (Operand, shift_count, Result) */
2005-04-17 02:20:36 +04:00
return ( integer0 > > integer1 ) ;
2005-08-05 08:44:28 +04:00
case AML_SUBTRACT_OP : /* Subtract (Integer0, Integer1, Result) */
2005-04-17 02:20:36 +04:00
return ( integer0 - integer1 ) ;
default :
return ( 0 ) ;
}
}
/*******************************************************************************
*
* FUNCTION : acpi_ex_do_logical_numeric_op
*
* PARAMETERS : Opcode - AML opcode
* Integer0 - Integer operand # 0
* Integer1 - Integer operand # 1
* logical_result - TRUE / FALSE result of the operation
*
* RETURN : Status
*
* DESCRIPTION : Execute a logical " Numeric " AML opcode . For these Numeric
* operators ( LAnd and LOr ) , both operands must be integers .
*
* Note : cleanest machine code seems to be produced by the code
* below , rather than using statements of the form :
* Result = ( Integer0 & & Integer1 ) ;
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status
2005-08-05 08:44:28 +04:00
acpi_ex_do_logical_numeric_op ( u16 opcode ,
acpi_integer integer0 ,
acpi_integer integer1 , u8 * logical_result )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = AE_OK ;
u8 local_result = FALSE ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
ACPI_FUNCTION_TRACE ( " ex_do_logical_numeric_op " ) ;
2005-04-17 02:20:36 +04:00
switch ( opcode ) {
2005-08-05 08:44:28 +04:00
case AML_LAND_OP : /* LAnd (Integer0, Integer1) */
2005-04-17 02:20:36 +04:00
if ( integer0 & & integer1 ) {
local_result = TRUE ;
}
break ;
2005-08-05 08:44:28 +04:00
case AML_LOR_OP : /* LOr (Integer0, Integer1) */
2005-04-17 02:20:36 +04:00
if ( integer0 | | integer1 ) {
local_result = TRUE ;
}
break ;
default :
status = AE_AML_INTERNAL ;
break ;
}
/* Return the logical result and status */
* logical_result = local_result ;
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( status ) ;
2005-04-17 02:20:36 +04:00
}
/*******************************************************************************
*
* FUNCTION : acpi_ex_do_logical_op
*
* PARAMETERS : Opcode - AML opcode
* Operand0 - operand # 0
* Operand1 - operand # 1
* logical_result - TRUE / FALSE result of the operation
*
* RETURN : Status
*
* DESCRIPTION : Execute a logical AML opcode . The purpose of having all of the
* functions here is to prevent a lot of pointer dereferencing
* to obtain the operands and to simplify the generation of the
* logical value . For the Numeric operators ( LAnd and LOr ) , both
* operands must be integers . For the other logical operators ,
* operands can be any combination of Integer / String / Buffer . The
* first operand determines the type to which the second operand
* will be converted .
*
* Note : cleanest machine code seems to be produced by the code
* below , rather than using statements of the form :
* Result = ( Operand0 = = Operand1 ) ;
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
acpi_status
2005-08-05 08:44:28 +04:00
acpi_ex_do_logical_op ( u16 opcode ,
union acpi_operand_object * operand0 ,
union acpi_operand_object * operand1 , u8 * logical_result )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
union acpi_operand_object * local_operand1 = operand1 ;
acpi_integer integer0 ;
acpi_integer integer1 ;
u32 length0 ;
u32 length1 ;
acpi_status status = AE_OK ;
u8 local_result = FALSE ;
int compare ;
2005-04-17 02:20:36 +04:00
2005-08-05 08:44:28 +04:00
ACPI_FUNCTION_TRACE ( " ex_do_logical_op " ) ;
2005-04-17 02:20:36 +04:00
/*
* Convert the second operand if necessary . The first operand
* determines the type of the second operand , ( See the Data Types
* section of the ACPI 3.0 + specification . ) Both object types are
* guaranteed to be either Integer / String / Buffer by the operand
* resolution mechanism .
*/
2005-08-05 08:44:28 +04:00
switch ( ACPI_GET_OBJECT_TYPE ( operand0 ) ) {
2005-04-17 02:20:36 +04:00
case ACPI_TYPE_INTEGER :
2005-08-05 08:44:28 +04:00
status =
acpi_ex_convert_to_integer ( operand1 , & local_operand1 , 16 ) ;
2005-04-17 02:20:36 +04:00
break ;
case ACPI_TYPE_STRING :
2005-08-05 08:44:28 +04:00
status = acpi_ex_convert_to_string ( operand1 , & local_operand1 ,
ACPI_IMPLICIT_CONVERT_HEX ) ;
2005-04-17 02:20:36 +04:00
break ;
case ACPI_TYPE_BUFFER :
2005-08-05 08:44:28 +04:00
status = acpi_ex_convert_to_buffer ( operand1 , & local_operand1 ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
status = AE_AML_INTERNAL ;
break ;
}
2005-08-05 08:44:28 +04:00
if ( ACPI_FAILURE ( status ) ) {
2005-04-17 02:20:36 +04:00
goto cleanup ;
}
/*
* Two cases : 1 ) Both Integers , 2 ) Both Strings or Buffers
*/
2005-08-05 08:44:28 +04:00
if ( ACPI_GET_OBJECT_TYPE ( operand0 ) = = ACPI_TYPE_INTEGER ) {
2005-04-17 02:20:36 +04:00
/*
* 1 ) Both operands are of type integer
* Note : local_operand1 may have changed above
*/
integer0 = operand0 - > integer . value ;
integer1 = local_operand1 - > integer . value ;
switch ( opcode ) {
2005-08-05 08:44:28 +04:00
case AML_LEQUAL_OP : /* LEqual (Operand0, Operand1) */
2005-04-17 02:20:36 +04:00
if ( integer0 = = integer1 ) {
local_result = TRUE ;
}
break ;
2005-08-05 08:44:28 +04:00
case AML_LGREATER_OP : /* LGreater (Operand0, Operand1) */
2005-04-17 02:20:36 +04:00
if ( integer0 > integer1 ) {
local_result = TRUE ;
}
break ;
2005-08-05 08:44:28 +04:00
case AML_LLESS_OP : /* LLess (Operand0, Operand1) */
2005-04-17 02:20:36 +04:00
if ( integer0 < integer1 ) {
local_result = TRUE ;
}
break ;
default :
status = AE_AML_INTERNAL ;
break ;
}
2005-08-05 08:44:28 +04:00
} else {
2005-04-17 02:20:36 +04:00
/*
* 2 ) Both operands are Strings or both are Buffers
* Note : Code below takes advantage of common Buffer / String
* object fields . local_operand1 may have changed above . Use
* memcmp to handle nulls in buffers .
*/
length0 = operand0 - > buffer . length ;
length1 = local_operand1 - > buffer . length ;
/* Lexicographic compare: compare the data bytes */
2005-10-21 08:00:00 +04:00
compare = ACPI_MEMCMP ( operand0 - > buffer . pointer ,
local_operand1 - > buffer . pointer ,
2005-08-05 08:44:28 +04:00
( length0 > length1 ) ? length1 : length0 ) ;
2005-04-17 02:20:36 +04:00
switch ( opcode ) {
2005-08-05 08:44:28 +04:00
case AML_LEQUAL_OP : /* LEqual (Operand0, Operand1) */
2005-04-17 02:20:36 +04:00
/* Length and all bytes must be equal */
2005-08-05 08:44:28 +04:00
if ( ( length0 = = length1 ) & & ( compare = = 0 ) ) {
2005-04-17 02:20:36 +04:00
/* Length and all bytes match ==> TRUE */
local_result = TRUE ;
}
break ;
2005-08-05 08:44:28 +04:00
case AML_LGREATER_OP : /* LGreater (Operand0, Operand1) */
2005-04-17 02:20:36 +04:00
if ( compare > 0 ) {
local_result = TRUE ;
2005-08-05 08:44:28 +04:00
goto cleanup ; /* TRUE */
2005-04-17 02:20:36 +04:00
}
if ( compare < 0 ) {
2005-08-05 08:44:28 +04:00
goto cleanup ; /* FALSE */
2005-04-17 02:20:36 +04:00
}
/* Bytes match (to shortest length), compare lengths */
if ( length0 > length1 ) {
local_result = TRUE ;
}
break ;
2005-08-05 08:44:28 +04:00
case AML_LLESS_OP : /* LLess (Operand0, Operand1) */
2005-04-17 02:20:36 +04:00
if ( compare > 0 ) {
2005-08-05 08:44:28 +04:00
goto cleanup ; /* FALSE */
2005-04-17 02:20:36 +04:00
}
if ( compare < 0 ) {
local_result = TRUE ;
2005-08-05 08:44:28 +04:00
goto cleanup ; /* TRUE */
2005-04-17 02:20:36 +04:00
}
/* Bytes match (to shortest length), compare lengths */
if ( length0 < length1 ) {
local_result = TRUE ;
}
break ;
default :
status = AE_AML_INTERNAL ;
break ;
}
}
2005-08-05 08:44:28 +04:00
cleanup :
2005-04-17 02:20:36 +04:00
/* New object was created if implicit conversion performed - delete */
if ( local_operand1 ! = operand1 ) {
2005-08-05 08:44:28 +04:00
acpi_ut_remove_reference ( local_operand1 ) ;
2005-04-17 02:20:36 +04:00
}
/* Return the logical result and status */
* logical_result = local_result ;
2005-08-05 08:44:28 +04:00
return_ACPI_STATUS ( status ) ;
2005-04-17 02:20:36 +04:00
}