patch-2.4.0-test3 linux/drivers/acpi/parser/psargs.c

Next file: linux/drivers/acpi/parser/psopcode.c
Previous file: linux/drivers/acpi/osd.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test2/linux/drivers/acpi/parser/psargs.c linux/drivers/acpi/parser/psargs.c
@@ -0,0 +1,735 @@
+/******************************************************************************
+ *
+ * Module Name: psargs - Parse AML opcode arguments
+ *
+ *****************************************************************************/
+
+/*
+ *  Copyright (C) 2000 R. Byron Moore
+ *
+ *  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 "acpi.h"
+#include "parser.h"
+#include "amlcode.h"
+#include "namesp.h"
+
+#define _COMPONENT          PARSER
+	 MODULE_NAME         ("psargs");
+
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_ps_get_next_package_length
+ *
+ * PARAMETERS:  Parser_state        - Current parser state object
+ *
+ * RETURN:      Decoded package length.  On completion, the AML pointer points
+ *              past the length byte or bytes.
+ *
+ * DESCRIPTION: Decode and return a package length field
+ *
+ ******************************************************************************/
+
+u32
+acpi_ps_get_next_package_length (
+	ACPI_PARSE_STATE        *parser_state)
+{
+	s32                     encoded_length;
+	s32                     length = 0;
+
+
+	encoded_length = (s32) GET8 (parser_state->aml);
+	parser_state->aml++;
+
+
+	switch (encoded_length >> 6) /* bits 6-7 contain encoding scheme */
+	{
+	case 0: /* 1-byte encoding (bits 0-5) */
+
+		length = (encoded_length & 0x3f);
+		break;
+
+
+	case 1: /* 2-byte encoding (next byte + bits 0-3) */
+
+		length = (GET8 (parser_state->aml) << 4) | (encoded_length & 0xf);
+		parser_state->aml++;
+		break;
+
+
+	case 2: /* 3-byte encoding (next 2 bytes + bits 0-3) */
+
+		length = ( (GET8 (parser_state->aml + 1) << 12)
+			   | (GET8 (parser_state->aml) << 4)
+			   | (encoded_length & 0xf));
+		parser_state->aml += 2;
+		break;
+
+
+	case 3: /* 4-byte encoding (next 3 bytes + bits 0-3) */
+
+		length = ( (GET8 (parser_state->aml + 2) << 20)
+			   | (GET8 (parser_state->aml + 1) << 12)
+			   | (GET8 (parser_state->aml) << 4)
+			   | (encoded_length & 0xf));
+		parser_state->aml += 3;
+		break;
+	}
+
+	return (length);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_ps_get_next_package_end
+ *
+ * PARAMETERS:  Parser_state        - Current parser state object
+ *
+ * RETURN:      Pointer to end-of-package +1
+ *
+ * DESCRIPTION: Get next package length and return a pointer past the end of
+ *              the package.  Consumes the package length field
+ *
+ ******************************************************************************/
+
+u8 *
+acpi_ps_get_next_package_end (
+	ACPI_PARSE_STATE        *parser_state)
+{
+	u8                      *start = parser_state->aml;
+	NATIVE_UINT             length;
+
+
+	length = (NATIVE_UINT) acpi_ps_get_next_package_length (parser_state);
+
+	return (start + length); /* end of package */
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_ps_get_next_namestring
+ *
+ * PARAMETERS:  Parser_state        - Current parser state object
+ *
+ * RETURN:      Pointer to the start of the name string (pointer points into
+ *              the AML.
+ *
+ * DESCRIPTION: Get next raw namestring within the AML stream.  Handles all name
+ *              prefix characters.  Set parser state to point past the string.
+ *              (Name is consumed from the AML.)
+ *
+ ******************************************************************************/
+
+char *
+acpi_ps_get_next_namestring (
+	ACPI_PARSE_STATE        *parser_state)
+{
+	char                    *start = (char *) parser_state->aml;
+	char                    *end = (char *) parser_state->aml;
+	s32                     length;
+
+
+	/* Handle multiple prefix characters */
+
+	while (acpi_ps_is_prefix_char (GET8 (end))) {
+		/* include prefix '\\' or '^' */
+
+		end++;
+	}
+
+	/* Decode the path */
+
+	switch (GET8 (end))
+	{
+	case 0:
+
+		/* Null_name */
+
+		if (end == start) {
+			start = NULL;
+		}
+		end++;
+		break;
+
+
+	case AML_DUAL_NAME_PREFIX:
+
+		/* two name segments */
+
+		end += 9;
+		break;
+
+
+	case AML_MULTI_NAME_PREFIX_OP:
+
+		/* multiple name segments */
+
+		length = (s32) GET8 (end + 1) * 4;
+		end += 2 + length;
+		break;
+
+
+	default:
+
+		/* single name segment */
+		/* assert (Acpi_ps_is_lead (GET8 (End))); */
+
+		end += 4;
+		break;
+	}
+
+	parser_state->aml = (u8*) end;
+
+	return (start);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_ps_get_next_namepath
+ *
+ * PARAMETERS:  Parser_state        - Current parser state object
+ *              Arg                 - Where the namepath will be stored
+ *              Arg_count           - If the namepath points to a control method
+ *                                    the method's argument is returned here.
+ *              Method_call         - Whether the namepath can be the start
+ *                                    of a method call
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Get next name (if method call, push appropriate # args).  Names
+ *              are looked up in either the parsed or internal namespace to
+ *              determine if the name represents a control method.  If a method
+ *              is found, the number of arguments to the method is returned.
+ *              This information is critical for parsing to continue correctly.
+ *
+ ******************************************************************************/
+
+
+#ifdef PARSER_ONLY
+
+void
+acpi_ps_get_next_namepath (
+	ACPI_PARSE_STATE        *parser_state,
+	ACPI_GENERIC_OP         *arg,
+	u32                     *arg_count,
+	u8                      method_call)
+{
+	char                    *path;
+	ACPI_GENERIC_OP         *name;
+	ACPI_GENERIC_OP         *op;
+	ACPI_GENERIC_OP         *count;
+
+
+	path = acpi_ps_get_next_namestring (parser_state);
+	if (!path || !method_call) {
+		/* Null name case, create a null namepath object */
+
+		acpi_ps_init_op (arg, AML_NAMEPATH_OP);
+		arg->value.name = path;
+		return;
+	}
+
+
+	if (acpi_gbl_parsed_namespace_root) {
+		/*
+		 * Lookup the name in the parsed namespace
+		 */
+
+		op = NULL;
+		if (method_call) {
+			op = acpi_ps_find (acpi_ps_get_parent_scope (parser_state),
+					   path, AML_METHOD_OP, 0);
+		}
+
+		if (op) {
+			if (op->opcode == AML_METHOD_OP) {
+				/*
+				 * The name refers to a control method, so this namepath is a
+				 * method invocation.  We need to 1) Get the number of arguments
+				 * associated with this method, and 2) Change the NAMEPATH
+				 * object into a METHODCALL object.
+				 */
+
+				count = acpi_ps_get_arg (op, 0);
+				if (count && count->opcode == AML_BYTE_OP) {
+					name = acpi_ps_alloc_op (AML_NAMEPATH_OP);
+					if (name) {
+						/* Change arg into a METHOD CALL and attach the name */
+
+						acpi_ps_init_op (arg, AML_METHODCALL_OP);
+
+						name->value.name = path;
+
+						/* Point METHODCALL/NAME to the METHOD NTE */
+
+						name->acpi_named_object = op;
+						acpi_ps_append_arg (arg, name);
+
+						*arg_count = count->value.integer &
+								 METHOD_FLAGS_ARG_COUNT;
+					}
+				}
+
+				return;
+			}
+
+			/*
+			 * Else this is normal named object reference.
+			 * Just init the NAMEPATH object with the pathname.
+			 * (See code below)
+			 */
+		}
+	}
+
+
+	/*
+	 * Either we didn't find the object in the namespace, or the object is
+	 * something other than a control method.  Just initialize the Op with the
+	 * pathname
+	 */
+
+	acpi_ps_init_op (arg, AML_NAMEPATH_OP);
+	arg->value.name = path;
+
+
+	return;
+}
+
+
+#else
+
+
+void
+acpi_ps_get_next_namepath (
+	ACPI_PARSE_STATE        *parser_state,
+	ACPI_GENERIC_OP         *arg,
+	u32                     *arg_count,
+	u8                      method_call)
+{
+	char                    *path;
+	ACPI_GENERIC_OP         *name;
+	ACPI_STATUS             status;
+	ACPI_NAMED_OBJECT       *method = NULL;
+	ACPI_NAMED_OBJECT       *entry;
+	ACPI_GENERIC_STATE      scope_info;
+
+
+	path = acpi_ps_get_next_namestring (parser_state);
+	if (!path || !method_call) {
+		/* Null name case, create a null namepath object */
+
+		acpi_ps_init_op (arg, AML_NAMEPATH_OP);
+		arg->value.name = path;
+		return;
+	}
+
+
+	if (method_call) {
+		/*
+		 * Lookup the name in the internal namespace
+		 */
+		scope_info.scope.name_table = NULL;
+		entry = parser_state->start_op->acpi_named_object;
+		if (entry) {
+			scope_info.scope.name_table = entry->child_table;
+		}
+
+		/*
+		 * Lookup object.  We don't want to add anything new to the namespace
+		 * here, however.  So we use MODE_EXECUTE.  Allow searching of the
+		 * parent tree, but don't open a new scope -- we just want to lookup the
+		 * object  (MUST BE mode EXECUTE to perform upsearch)
+		 */
+
+		status = acpi_ns_lookup (&scope_info, path, ACPI_TYPE_ANY, IMODE_EXECUTE,
+				 NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE, NULL,
+				 &entry);
+		if (ACPI_SUCCESS (status)) {
+			if (entry->type == ACPI_TYPE_METHOD) {
+				method = entry;
+				name = acpi_ps_alloc_op (AML_NAMEPATH_OP);
+				if (name) {
+					/* Change arg into a METHOD CALL and attach name to it */
+
+					acpi_ps_init_op (arg, AML_METHODCALL_OP);
+
+					name->value.name        = path;
+
+					/* Point METHODCALL/NAME to the METHOD NTE */
+
+					name->acpi_named_object  = method;
+					acpi_ps_append_arg (arg, name);
+
+					*arg_count = ((ACPI_OBJECT_INTERNAL *) method->object)->method.param_count;
+				}
+
+				return;
+			}
+
+			/*
+			 * Else this is normal named object reference.
+			 * Just init the NAMEPATH object with the pathname.
+			 * (See code below)
+			 */
+		}
+	}
+
+	/*
+	 * Either we didn't find the object in the namespace, or the object is
+	 * something other than a control method.  Just initialize the Op with the
+	 * pathname
+	 */
+
+	acpi_ps_init_op (arg, AML_NAMEPATH_OP);
+	arg->value.name = path;
+
+
+	return;
+}
+
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_ps_get_next_simple_arg
+ *
+ * PARAMETERS:  Parser_state        - Current parser state object
+ *              Arg_type            - The argument type (AML_*_ARG)
+ *              Arg                 - Where the argument is returned
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Get the next simple argument (constant, string, or namestring)
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_get_next_simple_arg (
+	ACPI_PARSE_STATE        *parser_state,
+	s32                     arg_type,
+	ACPI_GENERIC_OP         *arg)
+{
+
+
+	switch (arg_type)
+	{
+
+	case ARGP_BYTEDATA:
+
+		acpi_ps_init_op (arg, AML_BYTE_OP);
+		arg->value.integer = (u32) GET8 (parser_state->aml);
+		parser_state->aml++;
+		break;
+
+
+	case ARGP_WORDDATA:
+
+		acpi_ps_init_op (arg, AML_WORD_OP);
+
+		/* Get 2 bytes from the AML stream */
+
+		MOVE_UNALIGNED16_TO_32 (&arg->value.integer, parser_state->aml);
+		parser_state->aml += 2;
+		break;
+
+
+	case ARGP_DWORDDATA:
+
+		acpi_ps_init_op (arg, AML_DWORD_OP);
+
+		/* Get 4 bytes from the AML stream */
+
+		MOVE_UNALIGNED32_TO_32 (&arg->value.integer, parser_state->aml);
+		parser_state->aml += 4;
+		break;
+
+
+	case ARGP_CHARLIST:
+
+		acpi_ps_init_op (arg, AML_STRING_OP);
+		arg->value.string = (char*) parser_state->aml;
+
+		while (GET8 (parser_state->aml) != '\0') {
+			parser_state->aml++;
+		}
+		parser_state->aml++;
+		break;
+
+
+	case ARGP_NAME:
+	case ARGP_NAMESTRING:
+
+		acpi_ps_init_op (arg, AML_NAMEPATH_OP);
+		arg->value.name = acpi_ps_get_next_namestring (parser_state);
+		break;
+	}
+
+	return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_ps_get_next_field
+ *
+ * PARAMETERS:  Parser_state        - Current parser state object
+ *
+ * RETURN:      A newly allocated FIELD op
+ *
+ * DESCRIPTION: Get next field (Named_field, Reserved_field, or Access_field)
+ *
+ ******************************************************************************/
+
+ACPI_GENERIC_OP *
+acpi_ps_get_next_field (
+	ACPI_PARSE_STATE        *parser_state)
+{
+	ACPI_PTRDIFF            aml_offset = parser_state->aml -
+			 parser_state->aml_start;
+	ACPI_GENERIC_OP         *field;
+	u16                     opcode;
+	u32                     name;
+
+
+	/* determine field type */
+
+	switch (GET8 (parser_state->aml))
+	{
+
+	default:
+
+		opcode = AML_NAMEDFIELD_OP;
+		break;
+
+
+	case 0x00:
+
+		opcode = AML_RESERVEDFIELD_OP;
+		parser_state->aml++;
+		break;
+
+
+	case 0x01:
+
+		opcode = AML_ACCESSFIELD_OP;
+		parser_state->aml++;
+		break;
+	}
+
+
+	/* Allocate a new field op */
+
+	field = acpi_ps_alloc_op (opcode);
+	if (field) {
+		field->aml_offset = aml_offset;
+
+		/* Decode the field type */
+
+		switch (opcode)
+		{
+		case AML_NAMEDFIELD_OP:
+
+			/* Get the 4-character name */
+
+			MOVE_UNALIGNED32_TO_32 (&name, parser_state->aml);
+			acpi_ps_set_name (field, name);
+			parser_state->aml += 4;
+
+			/* Get the length which is encoded as a package length */
+
+			field->value.size = acpi_ps_get_next_package_length (parser_state);
+			break;
+
+
+		case AML_RESERVEDFIELD_OP:
+
+			/* Get the length which is encoded as a package length */
+
+			field->value.size = acpi_ps_get_next_package_length (parser_state);
+			break;
+
+
+		case AML_ACCESSFIELD_OP:
+
+			/* Get Access_type and Access_atrib and merge into the field Op */
+
+			field->value.integer = ((GET8 (parser_state->aml) << 8) |
+					  GET8 (parser_state->aml));
+			parser_state->aml += 2;
+			break;
+		}
+	}
+
+	return (field);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_ps_get_next_arg
+ *
+ * PARAMETERS:  Parser_state        - Current parser state object
+ *              Arg_type            - The argument type (AML_*_ARG)
+ *              Arg_count           - If the argument points to a control method
+ *                                    the method's argument is returned here.
+ *
+ * RETURN:      An op object containing the next argument.
+ *
+ * DESCRIPTION: Get next argument (including complex list arguments that require
+ *              pushing the parser stack)
+ *
+ ******************************************************************************/
+
+ACPI_GENERIC_OP *
+acpi_ps_get_next_arg (
+	ACPI_PARSE_STATE        *parser_state,
+	s32                     arg_type,
+	u32                     *arg_count)
+{
+	ACPI_GENERIC_OP         *arg = NULL;
+	ACPI_GENERIC_OP         *prev = NULL;
+	ACPI_GENERIC_OP         *field;
+	s32                     subop;
+
+
+	switch (arg_type)
+	{
+	case ARGP_BYTEDATA:
+	case ARGP_WORDDATA:
+	case ARGP_DWORDDATA:
+	case ARGP_CHARLIST:
+	case ARGP_NAME:
+	case ARGP_NAMESTRING:
+
+		/* constants, strings, and namestrings are all the same size */
+
+		arg = acpi_ps_alloc_op (AML_BYTE_OP);
+		if (arg) {
+			acpi_ps_get_next_simple_arg (parser_state, arg_type, arg);
+		}
+		break;
+
+
+	case ARGP_PKGLENGTH:
+
+		/* package length, nothing returned */
+
+		parser_state->pkg_end = acpi_ps_get_next_package_end (parser_state);
+		break;
+
+
+	case ARGP_FIELDLIST:
+
+		if (parser_state->aml < parser_state->pkg_end) {
+			/* non-empty list */
+
+			while (parser_state->aml < parser_state->pkg_end) {
+				field = acpi_ps_get_next_field (parser_state);
+				if (!field) {
+					break;
+				}
+
+				if (prev) {
+					prev->next = field;
+				}
+
+				else {
+					arg = field;
+				}
+
+				prev = field;
+			}
+
+			/* skip to End of byte data */
+
+			parser_state->aml = parser_state->pkg_end;
+		}
+		break;
+
+
+	case ARGP_BYTELIST:
+
+		if (parser_state->aml < parser_state->pkg_end) {
+			/* non-empty list */
+
+			arg = acpi_ps_alloc_op (AML_BYTELIST_OP);
+			if (arg) {
+				/* fill in bytelist data */
+
+				arg->value.size = (parser_state->pkg_end - parser_state->aml);
+				acpi_ps_to_bytelist_op (arg)->data = parser_state->aml;
+			}
+
+			/* skip to End of byte data */
+
+			parser_state->aml = parser_state->pkg_end;
+		}
+		break;
+
+
+	case ARGP_TARGET:
+	case ARGP_SUPERNAME:
+		{
+			subop = acpi_ps_peek_opcode (parser_state);
+			if (subop == 0              ||
+				acpi_ps_is_leading_char (subop) ||
+				acpi_ps_is_prefix_char (subop))
+			{
+				/* Null_name or Name_string */
+
+				arg = acpi_ps_alloc_op (AML_NAMEPATH_OP);
+				if (arg) {
+					acpi_ps_get_next_namepath (parser_state, arg, arg_count, 0);
+				}
+			}
+
+			else {
+				/* single complex argument, nothing returned */
+
+				*arg_count = 1;
+			}
+		}
+		break;
+
+
+	case ARGP_DATAOBJ:
+	case ARGP_TERMARG:
+
+		/* single complex argument, nothing returned */
+
+		*arg_count = 1;
+		break;
+
+
+	case ARGP_DATAOBJLIST:
+	case ARGP_TERMLIST:
+	case ARGP_OBJLIST:
+
+		if (parser_state->aml < parser_state->pkg_end) {
+			/* non-empty list of variable arguments, nothing returned */
+
+			*arg_count = ACPI_VAR_ARGS;
+		}
+		break;
+	}
+
+	return (arg);
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)