2005-04-17 02:20:36 +04:00
/*
* acpi_utils . c - ACPI Utility Functions ( $ Revision : 10 $ )
*
* Copyright ( C ) 2001 , 2002 Andy Grover < andrew . grover @ intel . com >
* Copyright ( C ) 2001 , 2002 Paul Diefenbaugh < paul . s . diefenbaugh @ intel . com >
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or ( at
* your option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA .
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/types.h>
# include <acpi/acpi_bus.h>
# include <acpi/acpi_drivers.h>
# define _COMPONENT ACPI_BUS_COMPONENT
2005-08-05 08:44:28 +04:00
ACPI_MODULE_NAME ( " acpi_utils " )
2005-04-17 02:20:36 +04:00
/* --------------------------------------------------------------------------
Object Evaluation Helpers
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
# ifdef ACPI_DEBUG_OUTPUT
# define acpi_util_eval_error(h,p,s) {\
char prefix [ 80 ] = { ' \0 ' } ; \
struct acpi_buffer buffer = { sizeof ( prefix ) , prefix } ; \
acpi_get_name ( h , ACPI_FULL_PATHNAME , & buffer ) ; \
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Evaluate [%s.%s]: %s \n " , \
( char * ) prefix , p , acpi_format_exception ( s ) ) ) ; }
# else
# define acpi_util_eval_error(h,p,s)
# endif
acpi_status
2005-08-05 08:44:28 +04:00
acpi_extract_package ( union acpi_object * package ,
struct acpi_buffer * format , struct acpi_buffer * buffer )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
u32 size_required = 0 ;
u32 tail_offset = 0 ;
char * format_string = NULL ;
u32 format_count = 0 ;
u32 i = 0 ;
u8 * head = NULL ;
u8 * tail = NULL ;
2005-04-17 02:20:36 +04:00
ACPI_FUNCTION_TRACE ( " acpi_extract_package " ) ;
2005-08-05 08:44:28 +04:00
if ( ! package | | ( package - > type ! = ACPI_TYPE_PACKAGE )
| | ( package - > package . count < 1 ) ) {
2006-06-27 07:58:43 +04:00
ACPI_WARNING ( ( AE_INFO , " Invalid package argument " ) ) ;
2005-04-17 02:20:36 +04:00
return_ACPI_STATUS ( AE_BAD_PARAMETER ) ;
}
if ( ! format | | ! format - > pointer | | ( format - > length < 1 ) ) {
2006-06-27 07:58:43 +04:00
ACPI_WARNING ( ( AE_INFO , " Invalid format argument " ) ) ;
2005-04-17 02:20:36 +04:00
return_ACPI_STATUS ( AE_BAD_PARAMETER ) ;
}
if ( ! buffer ) {
2006-06-27 07:58:43 +04:00
ACPI_WARNING ( ( AE_INFO , " Invalid buffer argument " ) ) ;
2005-04-17 02:20:36 +04:00
return_ACPI_STATUS ( AE_BAD_PARAMETER ) ;
}
2005-08-05 08:44:28 +04:00
format_count = ( format - > length / sizeof ( char ) ) - 1 ;
2005-04-17 02:20:36 +04:00
if ( format_count > package - > package . count ) {
2006-06-27 07:58:43 +04:00
ACPI_WARNING ( ( AE_INFO , " Format specifies more objects [%d] "
" than exist in package [%d]. " ,
format_count , package - > package . count ) ) ;
2005-04-17 02:20:36 +04:00
return_ACPI_STATUS ( AE_BAD_DATA ) ;
}
2005-08-05 08:44:28 +04:00
format_string = ( char * ) format - > pointer ;
2005-04-17 02:20:36 +04:00
/*
* Calculate size_required .
*/
2005-08-05 08:44:28 +04:00
for ( i = 0 ; i < format_count ; i + + ) {
2005-04-17 02:20:36 +04:00
union acpi_object * element = & ( package - > package . elements [ i ] ) ;
if ( ! element ) {
return_ACPI_STATUS ( AE_BAD_DATA ) ;
}
switch ( element - > type ) {
case ACPI_TYPE_INTEGER :
switch ( format_string [ i ] ) {
case ' N ' :
size_required + = sizeof ( acpi_integer ) ;
tail_offset + = sizeof ( acpi_integer ) ;
break ;
case ' S ' :
2005-08-05 08:44:28 +04:00
size_required + =
sizeof ( char * ) + sizeof ( acpi_integer ) +
sizeof ( char ) ;
tail_offset + = sizeof ( char * ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
2006-06-27 07:58:43 +04:00
ACPI_WARNING ( ( AE_INFO , " Invalid package element "
" [%d]: got number, expecing "
" [%c] " ,
i , format_string [ i ] ) ) ;
2005-04-17 02:20:36 +04:00
return_ACPI_STATUS ( AE_BAD_DATA ) ;
break ;
}
break ;
case ACPI_TYPE_STRING :
case ACPI_TYPE_BUFFER :
switch ( format_string [ i ] ) {
case ' S ' :
2005-08-05 08:44:28 +04:00
size_required + =
sizeof ( char * ) +
( element - > string . length * sizeof ( char ) ) +
sizeof ( char ) ;
tail_offset + = sizeof ( char * ) ;
2005-04-17 02:20:36 +04:00
break ;
case ' B ' :
2005-08-05 08:44:28 +04:00
size_required + =
sizeof ( u8 * ) +
( element - > buffer . length * sizeof ( u8 ) ) ;
tail_offset + = sizeof ( u8 * ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
2006-06-27 07:58:43 +04:00
ACPI_WARNING ( ( AE_INFO , " Invalid package element "
" [%d] got string/buffer, "
" expecing [%c] " ,
i , format_string [ i ] ) ) ;
2005-04-17 02:20:36 +04:00
return_ACPI_STATUS ( AE_BAD_DATA ) ;
break ;
}
break ;
case ACPI_TYPE_PACKAGE :
default :
2005-08-05 08:44:28 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO ,
" Found unsupported element at index=%d \n " ,
i ) ) ;
2005-04-17 02:20:36 +04:00
/* TBD: handle nested packages... */
return_ACPI_STATUS ( AE_SUPPORT ) ;
break ;
}
}
/*
* Validate output buffer .
*/
if ( buffer - > length < size_required ) {
buffer - > length = size_required ;
return_ACPI_STATUS ( AE_BUFFER_OVERFLOW ) ;
2005-08-05 08:44:28 +04:00
} else if ( buffer - > length ! = size_required | | ! buffer - > pointer ) {
2005-04-17 02:20:36 +04:00
return_ACPI_STATUS ( AE_BAD_PARAMETER ) ;
}
head = buffer - > pointer ;
tail = buffer - > pointer + tail_offset ;
/*
* Extract package data .
*/
2005-08-05 08:44:28 +04:00
for ( i = 0 ; i < format_count ; i + + ) {
2005-04-17 02:20:36 +04:00
u8 * * pointer = NULL ;
union acpi_object * element = & ( package - > package . elements [ i ] ) ;
if ( ! element ) {
return_ACPI_STATUS ( AE_BAD_DATA ) ;
}
switch ( element - > type ) {
case ACPI_TYPE_INTEGER :
switch ( format_string [ i ] ) {
case ' N ' :
2005-08-05 08:44:28 +04:00
* ( ( acpi_integer * ) head ) =
element - > integer . value ;
2005-04-17 02:20:36 +04:00
head + = sizeof ( acpi_integer ) ;
break ;
case ' S ' :
2005-08-05 08:44:28 +04:00
pointer = ( u8 * * ) head ;
2005-04-17 02:20:36 +04:00
* pointer = tail ;
2005-08-05 08:44:28 +04:00
* ( ( acpi_integer * ) tail ) =
element - > integer . value ;
head + = sizeof ( acpi_integer * ) ;
2005-04-17 02:20:36 +04:00
tail + = sizeof ( acpi_integer ) ;
/* NULL terminate string */
* tail = ( char ) 0 ;
tail + = sizeof ( char ) ;
break ;
default :
/* Should never get here */
break ;
}
break ;
case ACPI_TYPE_STRING :
case ACPI_TYPE_BUFFER :
switch ( format_string [ i ] ) {
case ' S ' :
2005-08-05 08:44:28 +04:00
pointer = ( u8 * * ) head ;
2005-04-17 02:20:36 +04:00
* pointer = tail ;
2005-08-05 08:44:28 +04:00
memcpy ( tail , element - > string . pointer ,
element - > string . length ) ;
head + = sizeof ( char * ) ;
2005-04-17 02:20:36 +04:00
tail + = element - > string . length * sizeof ( char ) ;
/* NULL terminate string */
* tail = ( char ) 0 ;
tail + = sizeof ( char ) ;
break ;
case ' B ' :
2005-08-05 08:44:28 +04:00
pointer = ( u8 * * ) head ;
2005-04-17 02:20:36 +04:00
* pointer = tail ;
2005-08-05 08:44:28 +04:00
memcpy ( tail , element - > buffer . pointer ,
element - > buffer . length ) ;
head + = sizeof ( u8 * ) ;
2005-04-17 02:20:36 +04:00
tail + = element - > buffer . length * sizeof ( u8 ) ;
break ;
default :
/* Should never get here */
break ;
}
break ;
case ACPI_TYPE_PACKAGE :
/* TBD: handle nested packages... */
default :
/* Should never get here */
break ;
}
}
return_ACPI_STATUS ( AE_OK ) ;
}
2005-08-05 08:44:28 +04:00
EXPORT_SYMBOL ( acpi_extract_package ) ;
2005-04-17 02:20:36 +04:00
acpi_status
2005-08-05 08:44:28 +04:00
acpi_evaluate_integer ( acpi_handle handle ,
acpi_string pathname ,
struct acpi_object_list * arguments , unsigned long * data )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = AE_OK ;
union acpi_object * element ;
struct acpi_buffer buffer = { 0 , NULL } ;
2005-04-17 02:20:36 +04:00
ACPI_FUNCTION_TRACE ( " acpi_evaluate_integer " ) ;
if ( ! data )
return_ACPI_STATUS ( AE_BAD_PARAMETER ) ;
element = kmalloc ( sizeof ( union acpi_object ) , GFP_KERNEL ) ;
2005-08-05 08:44:28 +04:00
if ( ! element )
2005-04-17 02:20:36 +04:00
return_ACPI_STATUS ( AE_NO_MEMORY ) ;
memset ( element , 0 , sizeof ( union acpi_object ) ) ;
buffer . length = sizeof ( union acpi_object ) ;
buffer . pointer = element ;
status = acpi_evaluate_object ( handle , pathname , arguments , & buffer ) ;
if ( ACPI_FAILURE ( status ) ) {
acpi_util_eval_error ( handle , pathname , status ) ;
2006-04-27 13:25:00 +04:00
kfree ( element ) ;
2005-04-17 02:20:36 +04:00
return_ACPI_STATUS ( status ) ;
}
if ( element - > type ! = ACPI_TYPE_INTEGER ) {
acpi_util_eval_error ( handle , pathname , AE_BAD_DATA ) ;
2006-04-27 13:25:00 +04:00
kfree ( element ) ;
2005-04-17 02:20:36 +04:00
return_ACPI_STATUS ( AE_BAD_DATA ) ;
}
* data = element - > integer . value ;
kfree ( element ) ;
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Return value [%lu] \n " , * data ) ) ;
return_ACPI_STATUS ( AE_OK ) ;
}
2005-08-05 08:44:28 +04:00
EXPORT_SYMBOL ( acpi_evaluate_integer ) ;
2005-04-17 02:20:36 +04:00
#if 0
acpi_status
2005-08-05 08:44:28 +04:00
acpi_evaluate_string ( acpi_handle handle ,
acpi_string pathname ,
acpi_object_list * arguments , acpi_string * data )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = AE_OK ;
acpi_object * element = NULL ;
acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
2005-04-17 02:20:36 +04:00
ACPI_FUNCTION_TRACE ( " acpi_evaluate_string " ) ;
if ( ! data )
return_ACPI_STATUS ( AE_BAD_PARAMETER ) ;
status = acpi_evaluate_object ( handle , pathname , arguments , & buffer ) ;
if ( ACPI_FAILURE ( status ) ) {
acpi_util_eval_error ( handle , pathname , status ) ;
return_ACPI_STATUS ( status ) ;
}
element = ( acpi_object * ) buffer . pointer ;
2005-08-05 08:44:28 +04:00
if ( ( element - > type ! = ACPI_TYPE_STRING )
| | ( element - > type ! = ACPI_TYPE_BUFFER )
| | ! element - > string . length ) {
2005-04-17 02:20:36 +04:00
acpi_util_eval_error ( handle , pathname , AE_BAD_DATA ) ;
return_ACPI_STATUS ( AE_BAD_DATA ) ;
}
* data = kmalloc ( element - > string . length + 1 , GFP_KERNEL ) ;
if ( ! data ) {
2006-06-27 07:58:43 +04:00
ACPI_ERROR ( ( AE_INFO , " Memory allocation " ) ) ;
2005-04-17 02:20:36 +04:00
return_VALUE ( - ENOMEM ) ;
}
memset ( * data , 0 , element - > string . length + 1 ) ;
memcpy ( * data , element - > string . pointer , element - > string . length ) ;
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Return value [%s] \n " , * data ) ) ;
acpi_os_free ( buffer . pointer ) ;
return_ACPI_STATUS ( AE_OK ) ;
}
# endif
acpi_status
2005-08-05 08:44:28 +04:00
acpi_evaluate_reference ( acpi_handle handle ,
acpi_string pathname ,
struct acpi_object_list * arguments ,
struct acpi_handle_list * list )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = AE_OK ;
union acpi_object * package = NULL ;
union acpi_object * element = NULL ;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER , NULL } ;
u32 i = 0 ;
2005-04-17 02:20:36 +04:00
ACPI_FUNCTION_TRACE ( " acpi_evaluate_reference " ) ;
if ( ! list ) {
return_ACPI_STATUS ( AE_BAD_PARAMETER ) ;
}
/* Evaluate object. */
status = acpi_evaluate_object ( handle , pathname , arguments , & buffer ) ;
if ( ACPI_FAILURE ( status ) )
goto end ;
2005-08-05 08:44:28 +04:00
package = ( union acpi_object * ) buffer . pointer ;
2005-04-17 02:20:36 +04:00
if ( ( buffer . length = = 0 ) | | ! package ) {
2006-06-27 07:58:43 +04:00
ACPI_ERROR ( ( AE_INFO , " No return object (len %X ptr %p) " ,
( unsigned ) buffer . length , package ) ) ;
2005-04-17 02:20:36 +04:00
status = AE_BAD_DATA ;
acpi_util_eval_error ( handle , pathname , status ) ;
goto end ;
}
if ( package - > type ! = ACPI_TYPE_PACKAGE ) {
2006-06-27 07:58:43 +04:00
ACPI_ERROR ( ( AE_INFO , " Expecting a [Package], found type %X " ,
package - > type ) ) ;
2005-04-17 02:20:36 +04:00
status = AE_BAD_DATA ;
acpi_util_eval_error ( handle , pathname , status ) ;
goto end ;
}
if ( ! package - > package . count ) {
2006-06-27 07:58:43 +04:00
ACPI_ERROR ( ( AE_INFO , " [Package] has zero elements (%p) " ,
package ) ) ;
2005-04-17 02:20:36 +04:00
status = AE_BAD_DATA ;
acpi_util_eval_error ( handle , pathname , status ) ;
goto end ;
}
if ( package - > package . count > ACPI_MAX_HANDLES ) {
return_ACPI_STATUS ( AE_NO_MEMORY ) ;
}
list - > count = package - > package . count ;
/* Extract package data. */
for ( i = 0 ; i < list - > count ; i + + ) {
element = & ( package - > package . elements [ i ] ) ;
if ( element - > type ! = ACPI_TYPE_ANY ) {
status = AE_BAD_DATA ;
2006-06-27 07:58:43 +04:00
ACPI_ERROR ( ( AE_INFO ,
" Expecting a [Reference] package element, found type %X " ,
element - > type ) ) ;
2005-04-17 02:20:36 +04:00
acpi_util_eval_error ( handle , pathname , status ) ;
break ;
}
/* Get the acpi_handle. */
list - > handles [ i ] = element - > reference . handle ;
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Found reference [%p] \n " ,
2005-08-05 08:44:28 +04:00
list - > handles [ i ] ) ) ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
end :
2005-04-17 02:20:36 +04:00
if ( ACPI_FAILURE ( status ) ) {
list - > count = 0 ;
//kfree(list->handles);
}
acpi_os_free ( buffer . pointer ) ;
return_ACPI_STATUS ( status ) ;
}
2005-08-05 08:44:28 +04:00
EXPORT_SYMBOL ( acpi_evaluate_reference ) ;