diff options
Diffstat (limited to 'drivers/acpi/acpica/uteval.c')
-rw-r--r-- | drivers/acpi/acpica/uteval.c | 752 |
1 files changed, 752 insertions, 0 deletions
diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c new file mode 100644 index 00000000000..e1e438cd54a --- /dev/null +++ b/drivers/acpi/acpica/uteval.c @@ -0,0 +1,752 @@ +/****************************************************************************** + * + * Module Name: uteval - Object evaluation + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * 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/accommon.h> +#include <acpi/acnamesp.h> +#include <acpi/acinterp.h> + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("uteval") + +/* Local prototypes */ +static void +acpi_ut_copy_id_string(char *destination, char *source, acpi_size max_length); + +static acpi_status +acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc, + struct acpi_compatible_id *one_cid); + +/* + * Strings supported by the _OSI predefined (internal) method. + */ +static char *acpi_interfaces_supported[] = { + /* Operating System Vendor Strings */ + + "Windows 2000", /* Windows 2000 */ + "Windows 2001", /* Windows XP */ + "Windows 2001 SP1", /* Windows XP SP1 */ + "Windows 2001 SP2", /* Windows XP SP2 */ + "Windows 2001.1", /* Windows Server 2003 */ + "Windows 2001.1 SP1", /* Windows Server 2003 SP1 - Added 03/2006 */ + "Windows 2006", /* Windows Vista - Added 03/2006 */ + + /* Feature Group Strings */ + + "Extended Address Space Descriptor" + /* + * All "optional" feature group strings (features that are implemented + * by the host) should be implemented in the host version of + * acpi_os_validate_interface and should not be added here. + */ +}; + +/******************************************************************************* + * + * FUNCTION: acpi_ut_osi_implementation + * + * PARAMETERS: walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Implementation of the _OSI predefined control method + * + ******************************************************************************/ + +acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state) +{ + acpi_status status; + union acpi_operand_object *string_desc; + union acpi_operand_object *return_desc; + u32 i; + + ACPI_FUNCTION_TRACE(ut_osi_implementation); + + /* Validate the string input argument */ + + string_desc = walk_state->arguments[0].object; + if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) { + return_ACPI_STATUS(AE_TYPE); + } + + /* Create a return object */ + + return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + if (!return_desc) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + /* Default return value is SUPPORTED */ + + return_desc->integer.value = ACPI_UINT32_MAX; + walk_state->return_desc = return_desc; + + /* Compare input string to static table of supported interfaces */ + + for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_interfaces_supported); i++) { + if (!ACPI_STRCMP + (string_desc->string.pointer, + acpi_interfaces_supported[i])) { + + /* The interface is supported */ + + return_ACPI_STATUS(AE_OK); + } + } + + /* + * Did not match the string in the static table, call the host OSL to + * check for a match with one of the optional strings (such as + * "Module Device", "3.0 Thermal Model", etc.) + */ + status = acpi_os_validate_interface(string_desc->string.pointer); + if (ACPI_SUCCESS(status)) { + + /* The interface is supported */ + + return_ACPI_STATUS(AE_OK); + } + + /* The interface is not supported */ + + return_desc->integer.value = 0; + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_osi_invalidate + * + * PARAMETERS: interface_string + * + * RETURN: Status + * + * DESCRIPTION: invalidate string in pre-defiend _OSI string list + * + ******************************************************************************/ + +acpi_status acpi_osi_invalidate(char *interface) +{ + int i; + + for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_interfaces_supported); i++) { + if (!ACPI_STRCMP(interface, acpi_interfaces_supported[i])) { + *acpi_interfaces_supported[i] = '\0'; + return AE_OK; + } + } + return AE_NOT_FOUND; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_evaluate_object + * + * PARAMETERS: prefix_node - Starting node + * Path - Path to object from starting node + * expected_return_types - Bitmap of allowed return types + * return_desc - Where a return value is stored + * + * RETURN: Status + * + * DESCRIPTION: Evaluates a namespace object and verifies the type of the + * return object. Common code that simplifies accessing objects + * that have required return objects of fixed types. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node, + char *path, + u32 expected_return_btypes, + union acpi_operand_object **return_desc) +{ + struct acpi_evaluate_info *info; + acpi_status status; + u32 return_btype; + + ACPI_FUNCTION_TRACE(ut_evaluate_object); + + /* Allocate the evaluation information block */ + + info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); + if (!info) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + info->prefix_node = prefix_node; + info->pathname = path; + + /* Evaluate the object/method */ + + status = acpi_ns_evaluate(info); + if (ACPI_FAILURE(status)) { + if (status == AE_NOT_FOUND) { + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "[%4.4s.%s] was not found\n", + acpi_ut_get_node_name(prefix_node), + path)); + } else { + ACPI_ERROR_METHOD("Method execution failed", + prefix_node, path, status); + } + + goto cleanup; + } + + /* Did we get a return object? */ + + if (!info->return_object) { + if (expected_return_btypes) { + ACPI_ERROR_METHOD("No object was returned from", + prefix_node, path, AE_NOT_EXIST); + + status = AE_NOT_EXIST; + } + + goto cleanup; + } + + /* Map the return object type to the bitmapped type */ + + switch (ACPI_GET_OBJECT_TYPE(info->return_object)) { + case ACPI_TYPE_INTEGER: + return_btype = ACPI_BTYPE_INTEGER; + break; + + case ACPI_TYPE_BUFFER: + return_btype = ACPI_BTYPE_BUFFER; + break; + + case ACPI_TYPE_STRING: + return_btype = ACPI_BTYPE_STRING; + break; + + case ACPI_TYPE_PACKAGE: + return_btype = ACPI_BTYPE_PACKAGE; + break; + + default: + return_btype = 0; + break; + } + + if ((acpi_gbl_enable_interpreter_slack) && (!expected_return_btypes)) { + /* + * We received a return object, but one was not expected. This can + * happen frequently if the "implicit return" feature is enabled. + * Just delete the return object and return AE_OK. + */ + acpi_ut_remove_reference(info->return_object); + goto cleanup; + } + + /* Is the return object one of the expected types? */ + + if (!(expected_return_btypes & return_btype)) { + ACPI_ERROR_METHOD("Return object type is incorrect", + prefix_node, path, AE_TYPE); + + ACPI_ERROR((AE_INFO, + "Type returned from %s was incorrect: %s, expected Btypes: %X", + path, + acpi_ut_get_object_type_name(info->return_object), + expected_return_btypes)); + + /* On error exit, we must delete the return object */ + + acpi_ut_remove_reference(info->return_object); + status = AE_TYPE; + goto cleanup; + } + + /* Object type is OK, return it */ + + *return_desc = info->return_object; + + cleanup: + ACPI_FREE(info); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_evaluate_numeric_object + * + * PARAMETERS: object_name - Object name to be evaluated + * device_node - Node for the device + * Address - Where the value is returned + * + * RETURN: Status + * + * DESCRIPTION: Evaluates a numeric namespace object for a selected device + * and stores result in *Address. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_evaluate_numeric_object(char *object_name, + struct acpi_namespace_node *device_node, + acpi_integer * address) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + + ACPI_FUNCTION_TRACE(ut_evaluate_numeric_object); + + status = acpi_ut_evaluate_object(device_node, object_name, + ACPI_BTYPE_INTEGER, &obj_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Get the returned Integer */ + + *address = obj_desc->integer.value; + + /* On exit, we must delete the return object */ + + acpi_ut_remove_reference(obj_desc); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_copy_id_string + * + * PARAMETERS: Destination - Where to copy the string + * Source - Source string + * max_length - Length of the destination buffer + * + * RETURN: None + * + * DESCRIPTION: Copies an ID string for the _HID, _CID, and _UID methods. + * Performs removal of a leading asterisk if present -- workaround + * for a known issue on a bunch of machines. + * + ******************************************************************************/ + +static void +acpi_ut_copy_id_string(char *destination, char *source, acpi_size max_length) +{ + + /* + * Workaround for ID strings that have a leading asterisk. This construct + * is not allowed by the ACPI specification (ID strings must be + * alphanumeric), but enough existing machines have this embedded in their + * ID strings that the following code is useful. + */ + if (*source == '*') { + source++; + } + + /* Do the actual copy */ + + ACPI_STRNCPY(destination, source, max_length); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_execute_HID + * + * PARAMETERS: device_node - Node for the device + * Hid - Where the HID is returned + * + * RETURN: Status + * + * DESCRIPTION: Executes the _HID control method that returns the hardware + * ID of the device. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_HID(struct acpi_namespace_node *device_node, + struct acpica_device_id *hid) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + + ACPI_FUNCTION_TRACE(ut_execute_HID); + + status = acpi_ut_evaluate_object(device_node, METHOD_NAME__HID, + ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, + &obj_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) { + + /* Convert the Numeric HID to string */ + + acpi_ex_eisa_id_to_string((u32) obj_desc->integer.value, + hid->value); + } else { + /* Copy the String HID from the returned object */ + + acpi_ut_copy_id_string(hid->value, obj_desc->string.pointer, + sizeof(hid->value)); + } + + /* On exit, we must delete the return object */ + + acpi_ut_remove_reference(obj_desc); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_translate_one_cid + * + * PARAMETERS: obj_desc - _CID object, must be integer or string + * one_cid - Where the CID string is returned + * + * RETURN: Status + * + * DESCRIPTION: Return a numeric or string _CID value as a string. + * (Compatible ID) + * + * NOTE: Assumes a maximum _CID string length of + * ACPI_MAX_CID_LENGTH. + * + ******************************************************************************/ + +static acpi_status +acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc, + struct acpi_compatible_id *one_cid) +{ + + switch (ACPI_GET_OBJECT_TYPE(obj_desc)) { + case ACPI_TYPE_INTEGER: + + /* Convert the Numeric CID to string */ + + acpi_ex_eisa_id_to_string((u32) obj_desc->integer.value, + one_cid->value); + return (AE_OK); + + case ACPI_TYPE_STRING: + + if (obj_desc->string.length > ACPI_MAX_CID_LENGTH) { + return (AE_AML_STRING_LIMIT); + } + + /* Copy the String CID from the returned object */ + + acpi_ut_copy_id_string(one_cid->value, obj_desc->string.pointer, + ACPI_MAX_CID_LENGTH); + return (AE_OK); + + default: + + return (AE_TYPE); + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_execute_CID + * + * PARAMETERS: device_node - Node for the device + * return_cid_list - Where the CID list is returned + * + * RETURN: Status + * + * DESCRIPTION: Executes the _CID control method that returns one or more + * compatible hardware IDs for the device. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_CID(struct acpi_namespace_node * device_node, + struct acpi_compatible_id_list ** return_cid_list) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + u32 count; + u32 size; + struct acpi_compatible_id_list *cid_list; + u32 i; + + ACPI_FUNCTION_TRACE(ut_execute_CID); + + /* Evaluate the _CID method for this device */ + + status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CID, + ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING + | ACPI_BTYPE_PACKAGE, &obj_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Get the number of _CIDs returned */ + + count = 1; + if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_PACKAGE) { + count = obj_desc->package.count; + } + + /* Allocate a worst-case buffer for the _CIDs */ + + size = (((count - 1) * sizeof(struct acpi_compatible_id)) + + sizeof(struct acpi_compatible_id_list)); + + cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size); + if (!cid_list) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + /* Init CID list */ + + cid_list->count = count; + cid_list->size = size; + + /* + * A _CID can return either a single compatible ID or a package of + * compatible IDs. Each compatible ID can be one of the following: + * 1) Integer (32 bit compressed EISA ID) or + * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss") + */ + + /* The _CID object can be either a single CID or a package (list) of CIDs */ + + if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_PACKAGE) { + + /* Translate each package element */ + + for (i = 0; i < count; i++) { + status = + acpi_ut_translate_one_cid(obj_desc->package. + elements[i], + &cid_list->id[i]); + if (ACPI_FAILURE(status)) { + break; + } + } + } else { + /* Only one CID, translate to a string */ + + status = acpi_ut_translate_one_cid(obj_desc, cid_list->id); + } + + /* Cleanup on error */ + + if (ACPI_FAILURE(status)) { + ACPI_FREE(cid_list); + } else { + *return_cid_list = cid_list; + } + + /* On exit, we must delete the _CID return object */ + + acpi_ut_remove_reference(obj_desc); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_execute_UID + * + * PARAMETERS: device_node - Node for the device + * Uid - Where the UID is returned + * + * RETURN: Status + * + * DESCRIPTION: Executes the _UID control method that returns the hardware + * ID of the device. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_UID(struct acpi_namespace_node *device_node, + struct acpica_device_id *uid) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + + ACPI_FUNCTION_TRACE(ut_execute_UID); + + status = acpi_ut_evaluate_object(device_node, METHOD_NAME__UID, + ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, + &obj_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) { + + /* Convert the Numeric UID to string */ + + acpi_ex_unsigned_integer_to_string(obj_desc->integer.value, + uid->value); + } else { + /* Copy the String UID from the returned object */ + + acpi_ut_copy_id_string(uid->value, obj_desc->string.pointer, + sizeof(uid->value)); + } + + /* On exit, we must delete the return object */ + + acpi_ut_remove_reference(obj_desc); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_execute_STA + * + * PARAMETERS: device_node - Node for the device + * Flags - Where the status flags are returned + * + * RETURN: Status + * + * DESCRIPTION: Executes _STA for selected device and stores results in + * *Flags. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 * flags) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + + ACPI_FUNCTION_TRACE(ut_execute_STA); + + status = acpi_ut_evaluate_object(device_node, METHOD_NAME__STA, + ACPI_BTYPE_INTEGER, &obj_desc); + if (ACPI_FAILURE(status)) { + if (AE_NOT_FOUND == status) { + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "_STA on %4.4s was not found, assuming device is present\n", + acpi_ut_get_node_name(device_node))); + + *flags = ACPI_UINT32_MAX; + status = AE_OK; + } + + return_ACPI_STATUS(status); + } + + /* Extract the status flags */ + + *flags = (u32) obj_desc->integer.value; + + /* On exit, we must delete the return object */ + + acpi_ut_remove_reference(obj_desc); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_execute_Sxds + * + * PARAMETERS: device_node - Node for the device + * Flags - Where the status flags are returned + * + * RETURN: Status + * + * DESCRIPTION: Executes _STA for selected device and stores results in + * *Flags. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_sxds(struct acpi_namespace_node *device_node, u8 * highest) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + u32 i; + + ACPI_FUNCTION_TRACE(ut_execute_sxds); + + for (i = 0; i < 4; i++) { + highest[i] = 0xFF; + status = acpi_ut_evaluate_object(device_node, + ACPI_CAST_PTR(char, + acpi_gbl_highest_dstate_names + [i]), + ACPI_BTYPE_INTEGER, &obj_desc); + if (ACPI_FAILURE(status)) { + if (status != AE_NOT_FOUND) { + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "%s on Device %4.4s, %s\n", + ACPI_CAST_PTR(char, + acpi_gbl_highest_dstate_names + [i]), + acpi_ut_get_node_name + (device_node), + acpi_format_exception + (status))); + + return_ACPI_STATUS(status); + } + } else { + /* Extract the Dstate value */ + + highest[i] = (u8) obj_desc->integer.value; + + /* Delete the return object */ + + acpi_ut_remove_reference(obj_desc); + } + } + + return_ACPI_STATUS(AE_OK); +} |