summaryrefslogtreecommitdiff
path: root/drivers/acpi/parser
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2005-03-09 13:46:24 -0500
committerLen Brown <lenb@dhcppc3.>2005-03-09 13:46:24 -0500
commit4ca5d141df1bf28ec3047f8ef08041bb407452a8 (patch)
tree306394bc00648129fcdabb331d24c2e0ea3e0e31 /drivers/acpi/parser
parentd1833bdaf4b380966686ba201640c6df139179e3 (diff)
[ACPI] ACPICA 20050309 from Bob Moore
The string-to-buffer implicit conversion code has been modified again after a change to the ACPI specification. In order to match the behavior of the other major ACPI implementation, the target buffer is no longer truncated if the source string is smaller than an existing target buffer. This change requires an update to the ACPI spec, and should eliminate the recent AE_AML_BUFFER_LIMIT issues. The "implicit return" support was rewritten to a new algorithm that solves the general case. Rather than attempt to determine when a method is about to exit, the result of every ASL operator is saved momentarily until the very next ASL operator is executed. Therefore, no matter how the method exits, there will always be a saved implicit return value. This feature is only enabled with the acpi_gbl_enable_interpreter_slack flag which Linux enables unless "acpi=strict". This should eliminate AE_AML_NO_RETURN_VALUE errors. Implemented implicit conversion support for the predicate (operand) of the If, Else, and While operators. String and Buffer arguments are automatically converted to Integers. Changed the string-to-integer conversion behavior to match the new ACPI errata: "If no integer object exists, a new integer is created. The ASCII string is interpreted as a hexadecimal constant. Each string character is interpreted as a hexadecimal value ('0'-'9', 'A'-'F', 'a', 'f'), starting with the first character as the most significant digit, and ending with the first non-hexadecimal character or end-of-string." This means that the first non-hex character terminates the conversion and this is the code that was changed. Fixed a problem where the ObjectType operator would fail (fault) when used on an Index of a Package which pointed to a null package element. The operator now properly returns zero (Uninitialized) in this case. Fixed a problem where the While operator used excessive memory by not properly popping the result stack during execution. There was no memory leak after execution, however. (Code provided by Valery Podrezov.) Fixed a problem where references to control methods within Package objects caused the method to be invoked, instead of producing a reference object pointing to the method. Restructured and simplified the pswalk.c module (acpi_ps_delete_parse_tree) to improve performance and reduce code size. (Code provided by Alexey Starikovskiy.) Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/parser')
-rw-r--r--drivers/acpi/parser/psparse.c42
-rw-r--r--drivers/acpi/parser/pswalk.c254
2 files changed, 65 insertions, 231 deletions
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
index fd2751f512e3..e79edb53cb3b 100644
--- a/drivers/acpi/parser/psparse.c
+++ b/drivers/acpi/parser/psparse.c
@@ -1187,8 +1187,8 @@ acpi_ps_parse_aml (
previous_walk_state = walk_state;
- ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "return_value=%p, State=%p\n",
- walk_state->return_desc, walk_state));
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "return_value=%p, implicit_value=%p State=%p\n",
+ walk_state->return_desc, walk_state->implicit_return_obj, walk_state));
/* Check if we have restarted a preempted walk */
@@ -1200,8 +1200,20 @@ acpi_ps_parse_aml (
* If the method return value is not used by the parent,
* The object is deleted
*/
- status = acpi_ds_restart_control_method (walk_state,
- previous_walk_state->return_desc);
+ if (!previous_walk_state->return_desc) {
+ status = acpi_ds_restart_control_method (walk_state,
+ previous_walk_state->implicit_return_obj);
+ }
+ else {
+ /*
+ * We have a valid return value, delete any implicit
+ * return value.
+ */
+ acpi_ds_clear_implicit_return (previous_walk_state);
+
+ status = acpi_ds_restart_control_method (walk_state,
+ previous_walk_state->return_desc);
+ }
if (ACPI_SUCCESS (status)) {
walk_state->walk_type |= ACPI_WALK_METHOD_RESTART;
}
@@ -1218,12 +1230,26 @@ acpi_ps_parse_aml (
* value (if any)
*/
else if (previous_walk_state->caller_return_desc) {
- *(previous_walk_state->caller_return_desc) = previous_walk_state->return_desc; /* NULL if no return value */
+ if (previous_walk_state->implicit_return_obj) {
+ *(previous_walk_state->caller_return_desc) = previous_walk_state->implicit_return_obj;
+ }
+ else {
+ /* NULL if no return value */
+
+ *(previous_walk_state->caller_return_desc) = previous_walk_state->return_desc;
+ }
}
- else if (previous_walk_state->return_desc) {
- /* Caller doesn't want it, must delete it */
+ else {
+ if (previous_walk_state->return_desc) {
+ /* Caller doesn't want it, must delete it */
- acpi_ut_remove_reference (previous_walk_state->return_desc);
+ acpi_ut_remove_reference (previous_walk_state->return_desc);
+ }
+ if (previous_walk_state->implicit_return_obj) {
+ /* Caller doesn't want it, must delete it */
+
+ acpi_ut_remove_reference (previous_walk_state->implicit_return_obj);
+ }
}
acpi_ds_delete_walk_state (previous_walk_state);
diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c
index e04b1b73606b..110d2ce917b6 100644
--- a/drivers/acpi/parser/pswalk.c
+++ b/drivers/acpi/parser/pswalk.c
@@ -44,7 +44,6 @@
#include <acpi/acpi.h>
#include <acpi/acparser.h>
-#include <acpi/acdispat.h>
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME ("pswalk")
@@ -52,256 +51,65 @@
/*******************************************************************************
*
- * FUNCTION: acpi_ps_get_next_walk_op
+ * FUNCTION: acpi_ps_delete_parse_tree
*
- * PARAMETERS: walk_state - Current state of the walk
- * Op - Current Op to be walked
- * ascending_callback - Procedure called when Op is complete
+ * PARAMETERS: subtree_root - Root of tree (or subtree) to delete
*
- * RETURN: Status
+ * RETURN: None
*
- * DESCRIPTION: Get the next Op in a walk of the parse tree.
+ * DESCRIPTION: Delete a portion of or an entire parse tree.
*
******************************************************************************/
-acpi_status
-acpi_ps_get_next_walk_op (
- struct acpi_walk_state *walk_state,
- union acpi_parse_object *op,
- acpi_parse_upwards ascending_callback)
+void
+acpi_ps_delete_parse_tree (
+ union acpi_parse_object *subtree_root)
{
- union acpi_parse_object *next;
- union acpi_parse_object *parent;
- union acpi_parse_object *grand_parent;
- acpi_status status;
+ union acpi_parse_object *op = subtree_root;
+ union acpi_parse_object *next = NULL;
+ union acpi_parse_object *parent = NULL;
- ACPI_FUNCTION_TRACE_PTR ("ps_get_next_walk_op", op);
+ ACPI_FUNCTION_TRACE_PTR ("ps_delete_parse_tree", subtree_root);
- /* Check for a argument only if we are descending in the tree */
+ /* Visit all nodes in the subtree */
- if (walk_state->next_op_info != ACPI_NEXT_OP_UPWARD) {
- /* Look for an argument or child of the current op */
+ while (op) {
+ /* Check if we are not ascending */
- next = acpi_ps_get_arg (op, 0);
- if (next) {
- /* Still going downward in tree (Op is not completed yet) */
+ if (op != parent) {
+ /* Look for an argument or child of the current op */
- walk_state->prev_op = op;
- walk_state->next_op = next;
- walk_state->next_op_info = ACPI_NEXT_OP_DOWNWARD;
+ next = acpi_ps_get_arg (op, 0);
+ if (next) {
+ /* Still going downward in tree (Op is not completed yet) */
- return_ACPI_STATUS (AE_OK);
+ op = next;
+ continue;
+ }
}
/*
- * No more children, this Op is complete. Save Next and Parent
- * in case the Op object gets deleted by the callback routine
+ * No more children, this Op is complete.
*/
- next = op->common.next;
- parent = op->common.parent;
-
- walk_state->op = op;
- walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode);
- walk_state->opcode = op->common.aml_opcode;
+ next = op->common.next;
+ parent = op->common.parent;
- status = ascending_callback (walk_state);
+ acpi_ps_free_op (op);
/*
* If we are back to the starting point, the walk is complete.
*/
- if (op == walk_state->origin) {
- /* Reached the point of origin, the walk is complete */
-
- walk_state->prev_op = op;
- walk_state->next_op = NULL;
-
- return_ACPI_STATUS (status);
+ if (op == subtree_root) {
+ return_VOID;
}
-
- /*
- * Check for a sibling to the current op. A sibling means
- * we are still going "downward" in the tree.
- */
if (next) {
- /* There is a sibling, it will be next */
-
- walk_state->prev_op = op;
- walk_state->next_op = next;
- walk_state->next_op_info = ACPI_NEXT_OP_DOWNWARD;
-
- /* Continue downward */
-
- return_ACPI_STATUS (status);
+ op = next;
}
-
- /*
- * Drop into the loop below because we are moving upwards in
- * the tree
- */
- }
- else {
- /*
- * We are resuming a walk, and we were (are) going upward in the tree.
- * So, we want to drop into the parent loop below.
- */
- parent = op;
- }
-
- /*
- * Look for a sibling of the current Op's parent
- * Continue moving up the tree until we find a node that has not been
- * visited, or we get back to where we started.
- */
- while (parent) {
- /* We are moving up the tree, therefore this parent Op is complete */
-
- grand_parent = parent->common.parent;
- next = parent->common.next;
-
- walk_state->op = parent;
- walk_state->op_info = acpi_ps_get_opcode_info (parent->common.aml_opcode);
- walk_state->opcode = parent->common.aml_opcode;
-
- status = ascending_callback (walk_state);
-
- /*
- * If we are back to the starting point, the walk is complete.
- */
- if (parent == walk_state->origin) {
- /* Reached the point of origin, the walk is complete */
-
- walk_state->prev_op = parent;
- walk_state->next_op = NULL;
-
- return_ACPI_STATUS (status);
- }
-
- /*
- * If there is a sibling to this parent (it is not the starting point
- * Op), then we will visit it.
- */
- if (next) {
- /* found sibling of parent */
-
- walk_state->prev_op = parent;
- walk_state->next_op = next;
- walk_state->next_op_info = ACPI_NEXT_OP_DOWNWARD;
-
- return_ACPI_STATUS (status);
+ else {
+ op = parent;
}
-
- /* No siblings, no errors, just move up one more level in the tree */
-
- op = parent;
- parent = grand_parent;
- walk_state->prev_op = op;
}
-
-
- /*
- * Got all the way to the top of the tree, we must be done!
- * However, the code should have terminated in the loop above
- */
- walk_state->next_op = NULL;
-
- return_ACPI_STATUS (AE_OK);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ps_delete_completed_op
- *
- * PARAMETERS: State - Walk state
- * Op - Completed op
- *
- * RETURN: AE_OK
- *
- * DESCRIPTION: Callback function for acpi_ps_get_next_walk_op(). Used during
- * acpi_ps_delete_parse tree to delete Op objects when all sub-objects
- * have been visited (and deleted.)
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ps_delete_completed_op (
- struct acpi_walk_state *walk_state)
-{
-
- acpi_ps_free_op (walk_state->op);
- return (AE_OK);
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ps_delete_parse_tree
- *
- * PARAMETERS: subtree_root - Root of tree (or subtree) to delete
- *
- * RETURN: None
- *
- * DESCRIPTION: Delete a portion of or an entire parse tree.
- *
- ******************************************************************************/
-
-void
-acpi_ps_delete_parse_tree (
- union acpi_parse_object *subtree_root)
-{
- struct acpi_walk_state *walk_state;
- struct acpi_thread_state *thread;
- acpi_status status;
-
-
- ACPI_FUNCTION_TRACE_PTR ("ps_delete_parse_tree", subtree_root);
-
-
- if (!subtree_root) {
- return_VOID;
- }
-
- /* Create and initialize a new walk list */
-
- thread = acpi_ut_create_thread_state ();
- if (!thread) {
- return_VOID;
- }
-
- walk_state = acpi_ds_create_walk_state (0, NULL, NULL, thread);
- if (!walk_state) {
- return_VOID;
- }
-
- walk_state->parse_flags = 0;
- walk_state->descending_callback = NULL;
- walk_state->ascending_callback = NULL;
-
- walk_state->origin = subtree_root;
- walk_state->next_op = subtree_root;
-
- /* Head downward in the tree */
-
- walk_state->next_op_info = ACPI_NEXT_OP_DOWNWARD;
-
- /* Visit all nodes in the subtree */
-
- while (walk_state->next_op) {
- status = acpi_ps_get_next_walk_op (walk_state, walk_state->next_op,
- acpi_ps_delete_completed_op);
- if (ACPI_FAILURE (status)) {
- break;
- }
- }
-
- /* We are done with this walk */
-
- acpi_ut_delete_generic_state (ACPI_CAST_PTR (union acpi_generic_state, thread));
- acpi_ds_delete_walk_state (walk_state);
-
return_VOID;
}
-
-