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
2007-02-13 06:42:12 +03:00
ACPI_MODULE_NAME ( " utils " ) ;
2005-04-17 02:20:36 +04:00
/* --------------------------------------------------------------------------
Object Evaluation Helpers
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2008-02-16 04:07:19 +03:00
static void
acpi_util_eval_error ( acpi_handle h , acpi_string p , acpi_status s )
{
2005-04-17 02:20:36 +04:00
# ifdef ACPI_DEBUG_OUTPUT
2008-02-16 04:07:19 +03:00
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 ) ) ) ;
2005-04-17 02:20:36 +04:00
# else
2008-02-16 04:07:19 +03:00
return ;
2005-04-17 02:20:36 +04:00
# endif
2008-02-16 04:07:19 +03:00
}
2005-04-17 02:20:36 +04:00
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
2005-08-05 08:44:28 +04:00
if ( ! package | | ( package - > type ! = ACPI_TYPE_PACKAGE )
| | ( package - > package . count < 1 ) ) {
2006-06-27 07:04:31 +04:00
printk ( KERN_WARNING PREFIX " Invalid package argument \n " ) ;
2006-06-27 08:41:40 +04:00
return AE_BAD_PARAMETER ;
2005-04-17 02:20:36 +04:00
}
if ( ! format | | ! format - > pointer | | ( format - > length < 1 ) ) {
2006-06-27 07:04:31 +04:00
printk ( KERN_WARNING PREFIX " Invalid format argument \n " ) ;
2006-06-27 08:41:40 +04:00
return AE_BAD_PARAMETER ;
2005-04-17 02:20:36 +04:00
}
if ( ! buffer ) {
2006-06-27 07:04:31 +04:00
printk ( KERN_WARNING PREFIX " Invalid buffer argument \n " ) ;
2006-06-27 08:41:40 +04:00
return AE_BAD_PARAMETER ;
2005-04-17 02:20:36 +04:00
}
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:04:31 +04:00
printk ( KERN_WARNING PREFIX " Format specifies more objects [%d] "
" than exist in package [%d]. \n " ,
format_count , package - > package . count ) ;
2006-06-27 08:41:40 +04:00
return AE_BAD_DATA ;
2005-04-17 02:20:36 +04:00
}
2006-10-01 02:28:50 +04:00
format_string = 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 ) {
2006-06-27 08:41:40 +04:00
return AE_BAD_DATA ;
2005-04-17 02:20:36 +04:00
}
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:04:31 +04:00
printk ( KERN_WARNING PREFIX " Invalid package element "
2006-06-27 07:58:43 +04:00
" [%d]: got number, expecing "
2006-06-27 07:04:31 +04:00
" [%c] \n " ,
i , format_string [ i ] ) ;
2006-06-27 08:41:40 +04:00
return AE_BAD_DATA ;
2005-04-17 02:20:36 +04:00
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:04:31 +04:00
printk ( KERN_WARNING PREFIX " Invalid package element "
2006-06-27 07:58:43 +04:00
" [%d] got string/buffer, "
2006-06-27 07:04:31 +04:00
" expecing [%c] \n " ,
i , format_string [ i ] ) ;
2006-06-27 08:41:40 +04:00
return AE_BAD_DATA ;
2005-04-17 02:20:36 +04:00
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... */
2006-06-27 08:41:40 +04:00
return AE_SUPPORT ;
2005-04-17 02:20:36 +04:00
break ;
}
}
/*
* Validate output buffer .
*/
if ( buffer - > length < size_required ) {
buffer - > length = size_required ;
2006-06-27 08:41:40 +04:00
return AE_BUFFER_OVERFLOW ;
2005-08-05 08:44:28 +04:00
} else if ( buffer - > length ! = size_required | | ! buffer - > pointer ) {
2006-06-27 08:41:40 +04:00
return AE_BAD_PARAMETER ;
2005-04-17 02:20:36 +04:00
}
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 ) {
2006-06-27 08:41:40 +04:00
return AE_BAD_DATA ;
2005-04-17 02:20:36 +04:00
}
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 ;
}
}
2006-06-27 08:41:40 +04:00
return AE_OK ;
2005-04-17 02:20:36 +04:00
}
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 ,
2008-10-10 10:22:59 +04:00
struct acpi_object_list * arguments , unsigned long long * data )
2005-04-17 02:20:36 +04:00
{
2005-08-05 08:44:28 +04:00
acpi_status status = AE_OK ;
2008-11-25 14:05:08 +03:00
union acpi_object element ;
2005-08-05 08:44:28 +04:00
struct acpi_buffer buffer = { 0 , NULL } ;
2005-04-17 02:20:36 +04:00
if ( ! data )
2006-06-27 08:41:40 +04:00
return AE_BAD_PARAMETER ;
2005-04-17 02:20:36 +04:00
buffer . length = sizeof ( union acpi_object ) ;
2008-11-25 14:05:08 +03:00
buffer . pointer = & element ;
2005-04-17 02:20:36 +04:00
status = acpi_evaluate_object ( handle , pathname , arguments , & buffer ) ;
if ( ACPI_FAILURE ( status ) ) {
acpi_util_eval_error ( handle , pathname , status ) ;
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
2008-11-25 14:05:08 +03:00
if ( element . type ! = ACPI_TYPE_INTEGER ) {
2005-04-17 02:20:36 +04:00
acpi_util_eval_error ( handle , pathname , AE_BAD_DATA ) ;
2006-06-27 08:41:40 +04:00
return AE_BAD_DATA ;
2005-04-17 02:20:36 +04:00
}
2008-11-25 14:05:08 +03:00
* data = element . integer . value ;
2005-04-17 02:20:36 +04:00
2008-10-10 10:22:59 +04:00
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Return value [%llu] \n " , * data ) ) ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return AE_OK ;
2005-04-17 02:20:36 +04:00
}
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
if ( ! data )
2006-06-27 08:41:40 +04:00
return AE_BAD_PARAMETER ;
2005-04-17 02:20:36 +04:00
status = acpi_evaluate_object ( handle , pathname , arguments , & buffer ) ;
if ( ACPI_FAILURE ( status ) ) {
acpi_util_eval_error ( handle , pathname , status ) ;
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
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 ) ;
2006-06-27 08:41:40 +04:00
return AE_BAD_DATA ;
2005-04-17 02:20:36 +04:00
}
2006-12-19 23:56:11 +03:00
* data = kzalloc ( element - > string . length + 1 , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! data ) {
2006-06-27 07:41:38 +04:00
printk ( KERN_ERR PREFIX " Memory allocation \n " ) ;
2006-06-27 08:41:40 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
}
memcpy ( * data , element - > string . pointer , element - > string . length ) ;
ACPI_DEBUG_PRINT ( ( ACPI_DB_INFO , " Return value [%s] \n " , * data ) ) ;
2006-06-30 11:19:10 +04:00
kfree ( buffer . pointer ) ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return AE_OK ;
2005-04-17 02:20:36 +04:00
}
# 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
if ( ! list ) {
2006-06-27 08:41:40 +04:00
return AE_BAD_PARAMETER ;
2005-04-17 02:20:36 +04:00
}
/* Evaluate object. */
status = acpi_evaluate_object ( handle , pathname , arguments , & buffer ) ;
if ( ACPI_FAILURE ( status ) )
goto end ;
2006-10-01 02:28:50 +04:00
package = buffer . pointer ;
2005-04-17 02:20:36 +04:00
if ( ( buffer . length = = 0 ) | | ! package ) {
2006-06-27 07:41:38 +04:00
printk ( KERN_ERR PREFIX " No return object (len %X ptr %p) \n " ,
( 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:41:38 +04:00
printk ( KERN_ERR PREFIX " Expecting a [Package], found type %X \n " ,
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:41:38 +04:00
printk ( KERN_ERR PREFIX " [Package] has zero elements (%p) \n " ,
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 ) {
2006-06-27 08:41:40 +04:00
return AE_NO_MEMORY ;
2005-04-17 02:20:36 +04:00
}
list - > count = package - > package . count ;
/* Extract package data. */
for ( i = 0 ; i < list - > count ; i + + ) {
element = & ( package - > package . elements [ i ] ) ;
2008-04-10 19:06:43 +04:00
if ( element - > type ! = ACPI_TYPE_LOCAL_REFERENCE ) {
2005-04-17 02:20:36 +04:00
status = AE_BAD_DATA ;
2006-06-27 07:41:38 +04:00
printk ( KERN_ERR PREFIX
" Expecting a [Reference] package element, found type %X \n " ,
element - > type ) ;
2005-04-17 02:20:36 +04:00
acpi_util_eval_error ( handle , pathname , status ) ;
break ;
}
2008-03-12 03:06:24 +03:00
if ( ! element - > reference . handle ) {
printk ( KERN_WARNING PREFIX " Invalid reference in "
" package %s \n " , pathname ) ;
status = AE_NULL_ENTRY ;
break ;
}
2005-04-17 02:20:36 +04:00
/* 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);
}
2006-06-30 11:19:10 +04:00
kfree ( buffer . pointer ) ;
2005-04-17 02:20:36 +04:00
2006-06-27 08:41:40 +04:00
return status ;
2005-04-17 02:20:36 +04:00
}
2005-08-05 08:44:28 +04:00
EXPORT_SYMBOL ( acpi_evaluate_reference ) ;