patch-2.4.14 linux/drivers/acpi/executer/exmisc.c

Next file: linux/drivers/acpi/executer/exmonad.c
Previous file: linux/drivers/acpi/executer/exfldio.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.13/linux/drivers/acpi/executer/exmisc.c linux/drivers/acpi/executer/exmisc.c
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
- *              $Revision: 83 $
+ *              $Revision: 92 $
  *
  *****************************************************************************/
 
@@ -38,424 +38,403 @@
 
 /*******************************************************************************
  *
- * FUNCTION:    Acpi_ex_triadic
+ * FUNCTION:    Acpi_ex_get_object_reference
  *
- * PARAMETERS:  Opcode              - The opcode to be executed
- *              Walk_state          - Current walk state
- *              Return_desc         - Where to store the return object
+ * PARAMETERS:  Obj_desc        - Create a reference to this object
+ *              Return_desc        - Where to store the reference
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Execute Triadic operator (3 operands)
- *
- * ALLOCATION:  Deletes one operand descriptor -- other remains on stack
+ * DESCRIPTION: Obtain and return a "reference" to the target object
+ *              Common code for the Ref_of_op and the Cond_ref_of_op.
  *
  ******************************************************************************/
 
 acpi_status
-acpi_ex_triadic (
-	u16                     opcode,
-	acpi_walk_state         *walk_state,
-	acpi_operand_object     **return_desc)
+acpi_ex_get_object_reference (
+	acpi_operand_object     *obj_desc,
+	acpi_operand_object     **return_desc,
+	acpi_walk_state         *walk_state)
 {
-	acpi_operand_object     **operand = &walk_state->operands[0];
-	acpi_operand_object     *ret_desc = NULL;
-	acpi_operand_object     *tmp_desc;
-	ACPI_SIGNAL_FATAL_INFO  *fatal;
 	acpi_status             status = AE_OK;
 
 
-	FUNCTION_TRACE ("Ex_triadic");
-
-
-#define obj_desc1           operand[0]
-#define obj_desc2           operand[1]
-#define res_desc            operand[2]
-
-
-	switch (opcode) {
-
-	case AML_FATAL_OP:
-
-		/* Def_fatal   :=  Fatal_op Fatal_type  Fatal_code  Fatal_arg   */
+	FUNCTION_TRACE_PTR ("Ex_get_object_reference", obj_desc);
 
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
-			"Fatal_op: Type %x Code %x Arg %x <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n",
-			(u32) obj_desc1->integer.value, (u32) obj_desc2->integer.value,
-			(u32) res_desc->integer.value));
 
-
-		fatal = ACPI_MEM_ALLOCATE (sizeof (ACPI_SIGNAL_FATAL_INFO));
-		if (fatal) {
-			fatal->type = (u32) obj_desc1->integer.value;
-			fatal->code = (u32) obj_desc2->integer.value;
-			fatal->argument = (u32) res_desc->integer.value;
+	if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_INTERNAL)) {
+		if (obj_desc->common.type != INTERNAL_TYPE_REFERENCE) {
+			*return_desc = NULL;
+			status = AE_TYPE;
+			goto cleanup;
 		}
 
 		/*
-		 * Signal the OS
+		 * Not a Name -- an indirect name pointer would have
+		 * been converted to a direct name pointer in Acpi_ex_resolve_operands
 		 */
-		acpi_os_signal (ACPI_SIGNAL_FATAL, fatal);
-
-		/* Might return while OS is shutting down */
-
-		ACPI_MEM_FREE (fatal);
-		break;
-
+		switch (obj_desc->reference.opcode) {
+		case AML_LOCAL_OP:
+		case AML_ARG_OP:
 
-	case AML_MID_OP:
-
-		/* Def_mid      := Mid_op Source Index Length Result */
-
-		/* Create the internal return object (string or buffer) */
-
-		break;
-
-
-	case AML_INDEX_OP:
-
-		/* Def_index    := Index_op Source Index Destination */
+			*return_desc = (void *) acpi_ds_method_data_get_node (obj_desc->reference.opcode,
+					  obj_desc->reference.offset, walk_state);
+			break;
 
-		/* Create the internal return object */
+		default:
 
-		ret_desc = acpi_ut_create_internal_object (INTERNAL_TYPE_REFERENCE);
-		if (!ret_desc) {
-			status = AE_NO_MEMORY;
+			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(Internal) Unknown Ref subtype %02x\n",
+				obj_desc->reference.opcode));
+			*return_desc = NULL;
+			status = AE_AML_INTERNAL;
 			goto cleanup;
 		}
 
-		/*
-		 * At this point, the Obj_desc1 operand is either a Package or a Buffer
-		 */
-		if (obj_desc1->common.type == ACPI_TYPE_PACKAGE) {
-			/* Object to be indexed is a Package */
+	}
 
-			if (obj_desc2->integer.value >= obj_desc1->package.count) {
-				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index value beyond package end\n"));
-				status = AE_AML_PACKAGE_LIMIT;
-				goto cleanup;
-			}
-
-			if ((res_desc->common.type == INTERNAL_TYPE_REFERENCE) &&
-				(res_desc->reference.opcode == AML_ZERO_OP)) {
-				/*
-				 * There is no actual result descriptor (the Zero_op Result
-				 * descriptor is a placeholder), so just delete the placeholder and
-				 * return a reference to the package element
-				 */
-				acpi_ut_remove_reference (res_desc);
-			}
-
-			else {
-				/*
-				 * Each element of the package is an internal object.  Get the one
-				 * we are after.
-				 */
-				tmp_desc                      = obj_desc1->package.elements[obj_desc2->integer.value];
-				ret_desc->reference.opcode    = AML_INDEX_OP;
-				ret_desc->reference.target_type = tmp_desc->common.type;
-				ret_desc->reference.object    = tmp_desc;
-
-				status = acpi_ex_store (ret_desc, res_desc, walk_state);
-				ret_desc->reference.object    = NULL;
-			}
+	else if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) {
+		/* Must be a named object;  Just return the Node */
 
-			/*
-			 * The local return object must always be a reference to the package element,
-			 * not the element itself.
-			 */
-			ret_desc->reference.opcode    = AML_INDEX_OP;
-			ret_desc->reference.target_type = ACPI_TYPE_PACKAGE;
-			ret_desc->reference.where     = &obj_desc1->package.elements[obj_desc2->integer.value];
-		}
-
-		else {
-			/* Object to be indexed is a Buffer */
-
-			if (obj_desc2->integer.value >= obj_desc1->buffer.length) {
-				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index value beyond end of buffer\n"));
-				status = AE_AML_BUFFER_LIMIT;
-				goto cleanup;
-			}
-
-			ret_desc->reference.opcode      = AML_INDEX_OP;
-			ret_desc->reference.target_type = ACPI_TYPE_BUFFER_FIELD;
-			ret_desc->reference.object      = obj_desc1;
-			ret_desc->reference.offset      = (u32) obj_desc2->integer.value;
+		*return_desc = obj_desc;
+	}
 
-			status = acpi_ex_store (ret_desc, res_desc, walk_state);
-		}
-		break;
+	else {
+		*return_desc = NULL;
+		status = AE_TYPE;
 	}
 
 
 cleanup:
 
-	/* Always delete operands */
-
-	acpi_ut_remove_reference (obj_desc1);
-	acpi_ut_remove_reference (obj_desc2);
-
-	/* Delete return object on error */
-
-	if (ACPI_FAILURE (status)) {
-		acpi_ut_remove_reference (res_desc);
-
-		if (ret_desc) {
-			acpi_ut_remove_reference (ret_desc);
-			ret_desc = NULL;
-		}
-	}
-
-	/* Set the return object and exit */
-
-	*return_desc = ret_desc;
+	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p Ref=%p\n", obj_desc, *return_desc));
 	return_ACPI_STATUS (status);
 }
 
 
 /*******************************************************************************
  *
- * FUNCTION:    Acpi_ex_hexadic
+ * FUNCTION:    Acpi_ex_do_concatenate
  *
- * PARAMETERS:  Opcode              - The opcode to be executed
+ * PARAMETERS:  *Obj_desc           - Object to be converted.  Must be an
+ *                                    Integer, Buffer, or String
  *              Walk_state          - Current walk state
- *              Return_desc         - Where to store the return object
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Execute Match operator
+ * DESCRIPTION: Concatenate two objects OF THE SAME TYPE.
  *
  ******************************************************************************/
 
 acpi_status
-acpi_ex_hexadic (
-	u16                     opcode,
-	acpi_walk_state         *walk_state,
-	acpi_operand_object     **return_desc)
+acpi_ex_do_concatenate (
+	acpi_operand_object     *obj_desc,
+	acpi_operand_object     *obj_desc2,
+	acpi_operand_object     **actual_return_desc,
+	acpi_walk_state         *walk_state)
 {
-	acpi_operand_object     **operand = &walk_state->operands[0];
-	acpi_operand_object     *ret_desc = NULL;
-	acpi_status             status = AE_OK;
-	u32                     index;
-	u32                     match_value = (u32) -1;
+	acpi_status             status;
+	u32                     i;
+	acpi_integer            this_integer;
+	acpi_operand_object     *return_desc;
+	NATIVE_CHAR             *new_buf;
+	u32                     integer_size = sizeof (acpi_integer);
 
 
-	FUNCTION_TRACE ("Ex_hexadic");
+	FUNCTION_ENTRY ();
 
-#define pkg_desc            operand[0]
-#define op1_desc            operand[1]
-#define V1_desc             operand[2]
-#define op2_desc            operand[3]
-#define V2_desc             operand[4]
-#define start_desc          operand[5]
 
+	/*
+	 * There are three cases to handle:
+	 * 1) Two Integers concatenated to produce a buffer
+	 * 2) Two Strings concatenated to produce a string
+	 * 3) Two Buffers concatenated to produce a buffer
+	 */
+	switch (obj_desc->common.type) {
+	case ACPI_TYPE_INTEGER:
 
-	switch (opcode) {
+		/* Handle both ACPI 1.0 and ACPI 2.0 Integer widths */
 
-		case AML_MATCH_OP:
+		if (walk_state->method_node->flags & ANOBJ_DATA_WIDTH_32) {
+			/*
+			 * We are running a method that exists in a 32-bit ACPI table.
+			 * Truncate the value to 32 bits by zeroing out the upper
+			 * 32-bit field
+			 */
+			integer_size = sizeof (u32);
+		}
 
-		/* Validate match comparison sub-opcodes */
+		/* Result of two integers is a buffer */
 
-		if ((op1_desc->integer.value > MAX_MATCH_OPERATOR) ||
-			(op2_desc->integer.value > MAX_MATCH_OPERATOR)) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "operation encoding out of range\n"));
-			status = AE_AML_OPERAND_VALUE;
-			goto cleanup;
+		return_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER);
+		if (!return_desc) {
+			return (AE_NO_MEMORY);
 		}
 
-		index = (u32) start_desc->integer.value;
-		if (index >= (u32) pkg_desc->package.count) {
-			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Start position value out of range\n"));
-			status = AE_AML_PACKAGE_LIMIT;
+		/* Need enough space for two integers */
+
+		return_desc->buffer.length = integer_size * 2;
+		new_buf = ACPI_MEM_CALLOCATE (return_desc->buffer.length);
+		if (!new_buf) {
+			REPORT_ERROR
+				(("Ex_do_concatenate: Buffer allocation failure\n"));
+			status = AE_NO_MEMORY;
 			goto cleanup;
 		}
 
-		ret_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
-		if (!ret_desc) {
+		return_desc->buffer.pointer = (u8 *) new_buf;
+
+		/* Convert the first integer */
+
+		this_integer = obj_desc->integer.value;
+		for (i = 0; i < integer_size; i++) {
+			new_buf[i] = (u8) this_integer;
+			this_integer >>= 8;
+		}
+
+		/* Convert the second integer */
+
+		this_integer = obj_desc2->integer.value;
+		for (; i < (integer_size * 2); i++) {
+			new_buf[i] = (u8) this_integer;
+			this_integer >>= 8;
+		}
+
+		break;
+
+
+	case ACPI_TYPE_STRING:
+
+		return_desc = acpi_ut_create_internal_object (ACPI_TYPE_STRING);
+		if (!return_desc) {
+			return (AE_NO_MEMORY);
+		}
+
+		/* Operand0 is string  */
+
+		new_buf = ACPI_MEM_ALLOCATE (obj_desc->string.length +
+				  obj_desc2->string.length + 1);
+		if (!new_buf) {
+			REPORT_ERROR
+				(("Ex_do_concatenate: String allocation failure\n"));
 			status = AE_NO_MEMORY;
 			goto cleanup;
+		}
+
+		STRCPY (new_buf, obj_desc->string.pointer);
+		STRCPY (new_buf + obj_desc->string.length,
+				  obj_desc2->string.pointer);
+
+		/* Point the return object to the new string */
+
+		return_desc->string.pointer = new_buf;
+		return_desc->string.length = obj_desc->string.length +=
+				  obj_desc2->string.length;
+		break;
+
+
+	case ACPI_TYPE_BUFFER:
+
+		/* Operand0 is a buffer */
+
+		return_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER);
+		if (!return_desc) {
+			return (AE_NO_MEMORY);
+		}
 
+		new_buf = ACPI_MEM_ALLOCATE (obj_desc->buffer.length +
+				  obj_desc2->buffer.length);
+		if (!new_buf) {
+			REPORT_ERROR
+				(("Ex_do_concatenate: Buffer allocation failure\n"));
+			status = AE_NO_MEMORY;
+			goto cleanup;
 		}
 
+		MEMCPY (new_buf, obj_desc->buffer.pointer,
+				  obj_desc->buffer.length);
+		MEMCPY (new_buf + obj_desc->buffer.length, obj_desc2->buffer.pointer,
+				   obj_desc2->buffer.length);
+
 		/*
-		 * Examine each element until a match is found.  Within the loop,
-		 * "continue" signifies that the current element does not match
-		 * and the next should be examined.
-		 * Upon finding a match, the loop will terminate via "break" at
-		 * the bottom.  If it terminates "normally", Match_value will be -1
-		 * (its initial value) indicating that no match was found.  When
-		 * returned as a Number, this will produce the Ones value as specified.
+		 * Point the return object to the new buffer
 		 */
-		for ( ; index < pkg_desc->package.count; ++index) {
-			/*
-			 * Treat any NULL or non-numeric elements as non-matching.
-			 * TBD [Unhandled] - if an element is a Name,
-			 *      should we examine its value?
-			 */
-			if (!pkg_desc->package.elements[index] ||
-				ACPI_TYPE_INTEGER != pkg_desc->package.elements[index]->common.type) {
-				continue;
-			}
 
-			/*
-			 * Within these switch statements:
-			 *      "break" (exit from the switch) signifies a match;
-			 *      "continue" (proceed to next iteration of enclosing
-			 *          "for" loop) signifies a non-match.
-			 */
-			switch (op1_desc->integer.value) {
+		return_desc->buffer.pointer    = (u8 *) new_buf;
+		return_desc->buffer.length     = obj_desc->buffer.length +
+				 obj_desc2->buffer.length;
+		break;
 
-			case MATCH_MTR:   /* always true */
 
-				break;
+	default:
+		status = AE_AML_INTERNAL;
+		return_desc = NULL;
+	}
 
 
-			case MATCH_MEQ:   /* true if equal   */
+	*actual_return_desc = return_desc;
+	return (AE_OK);
 
-				if (pkg_desc->package.elements[index]->integer.value
-					 != V1_desc->integer.value) {
-					continue;
-				}
-				break;
 
+cleanup:
 
-			case MATCH_MLE:   /* true if less than or equal  */
+	acpi_ut_remove_reference (return_desc);
+	return (status);
+}
 
-				if (pkg_desc->package.elements[index]->integer.value
-					 > V1_desc->integer.value) {
-					continue;
-				}
-				break;
 
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_ex_do_math_op
+ *
+ * PARAMETERS:  Opcode              - AML opcode
+ *              Operand0            - Integer operand #0
+ *              Operand0            - Integer operand #1
+ *
+ * RETURN:      Integer result of the operation
+ *
+ * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the
+ *              math functions here is to prevent a lot of pointer dereferencing
+ *              to obtain the operands.
+ *
+ ******************************************************************************/
 
-			case MATCH_MLT:   /* true if less than   */
+acpi_integer
+acpi_ex_do_math_op (
+	u16                     opcode,
+	acpi_integer            operand0,
+	acpi_integer            operand1)
+{
 
-				if (pkg_desc->package.elements[index]->integer.value
-					 >= V1_desc->integer.value) {
-					continue;
-				}
-				break;
 
+	switch (opcode) {
+	case AML_ADD_OP:                /* Add (Operand0, Operand1, Result) */
 
-			case MATCH_MGE:   /* true if greater than or equal   */
+		return (operand0 + operand1);
 
-				if (pkg_desc->package.elements[index]->integer.value
-					 < V1_desc->integer.value) {
-					continue;
-				}
-				break;
 
+	case AML_BIT_AND_OP:            /* And (Operand0, Operand1, Result) */
 
-			case MATCH_MGT:   /* true if greater than    */
+		return (operand0 & operand1);
 
-				if (pkg_desc->package.elements[index]->integer.value
-					 <= V1_desc->integer.value) {
-					continue;
-				}
-				break;
 
+	case AML_BIT_NAND_OP:           /* NAnd (Operand0, Operand1, Result) */
 
-			default:    /* undefined   */
+		return (~(operand0 & operand1));
 
-				continue;
-			}
 
+	case AML_BIT_OR_OP:             /* Or (Operand0, Operand1, Result) */
 
-			switch(op2_desc->integer.value) {
+		return (operand0 | operand1);
 
-			case MATCH_MTR:
 
-				break;
+	case AML_BIT_NOR_OP:            /* NOr (Operand0, Operand1, Result) */
 
+		return (~(operand0 | operand1));
 
-			case MATCH_MEQ:
 
-				if (pkg_desc->package.elements[index]->integer.value
-					 != V2_desc->integer.value) {
-					continue;
-				}
-				break;
+	case AML_BIT_XOR_OP:            /* XOr (Operand0, Operand1, Result) */
 
+		return (operand0 ^ operand1);
 
-			case MATCH_MLE:
 
-				if (pkg_desc->package.elements[index]->integer.value
-					 > V2_desc->integer.value) {
-					continue;
-				}
-				break;
+	case AML_MULTIPLY_OP:           /* Multiply (Operand0, Operand1, Result) */
 
+		return (operand0 * operand1);
 
-			case MATCH_MLT:
 
-				if (pkg_desc->package.elements[index]->integer.value
-					 >= V2_desc->integer.value) {
-					continue;
-				}
-				break;
+	case AML_SHIFT_LEFT_OP:         /* Shift_left (Operand, Shift_count, Result) */
 
+		return (operand0 << operand1);
 
-			case MATCH_MGE:
 
-				if (pkg_desc->package.elements[index]->integer.value
-					 < V2_desc->integer.value) {
-					continue;
-				}
-				break;
+	case AML_SHIFT_RIGHT_OP:        /* Shift_right (Operand, Shift_count, Result) */
 
+		return (operand0 >> operand1);
 
-			case MATCH_MGT:
 
-				if (pkg_desc->package.elements[index]->integer.value
-					 <= V2_desc->integer.value) {
-					continue;
-				}
-				break;
+	case AML_SUBTRACT_OP:           /* Subtract (Operand0, Operand1, Result) */
 
+		return (operand0 - operand1);
 
-			default:
+	default:
 
-				continue;
-			}
+		return (0);
+	}
+}
 
-			/* Match found: exit from loop */
 
-			match_value = index;
-			break;
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_ex_do_logical_op
+ *
+ * PARAMETERS:  Opcode              - AML opcode
+ *              Operand0            - Integer operand #0
+ *              Operand0            - Integer operand #1
+ *
+ * RETURN:      TRUE/FALSE result of the operation
+ *
+ * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the
+ *              functions here is to prevent a lot of pointer dereferencing
+ *              to obtain the operands and to simplify the generation of the
+ *              logical value.
+ *
+ *              Note: cleanest machine code seems to be produced by the code
+ *              below, rather than using statements of the form:
+ *                  Result = (Operand0 == Operand1);
+ *
+ ******************************************************************************/
+
+u8
+acpi_ex_do_logical_op (
+	u16                     opcode,
+	acpi_integer            operand0,
+	acpi_integer            operand1)
+{
+
+
+	switch (opcode) {
+
+	case AML_LAND_OP:               /* LAnd (Operand0, Operand1) */
+
+		if (operand0 && operand1) {
+			return (TRUE);
 		}
+		break;
 
-		/* Match_value is the return value */
 
-		ret_desc->integer.value = match_value;
+	case AML_LEQUAL_OP:             /* LEqual (Operand0, Operand1) */
+
+		if (operand0 == operand1) {
+			return (TRUE);
+		}
 		break;
 
-	}
 
+	case AML_LGREATER_OP:           /* LGreater (Operand0, Operand1) */
 
-cleanup:
+		if (operand0 > operand1) {
+			return (TRUE);
+		}
+		break;
 
-	/* Free the operands */
 
-	acpi_ut_remove_reference (start_desc);
-	acpi_ut_remove_reference (V2_desc);
-	acpi_ut_remove_reference (op2_desc);
-	acpi_ut_remove_reference (V1_desc);
-	acpi_ut_remove_reference (op1_desc);
-	acpi_ut_remove_reference (pkg_desc);
-
-
-	/* Delete return object on error */
-
-	if (ACPI_FAILURE (status) &&
-		(ret_desc)) {
-		acpi_ut_remove_reference (ret_desc);
-		ret_desc = NULL;
-	}
+	case AML_LLESS_OP:              /* LLess (Operand0, Operand1) */
 
+		if (operand0 < operand1) {
+			return (TRUE);
+		}
+		break;
 
-	/* Set the return object and exit */
 
-	*return_desc = ret_desc;
-	return_ACPI_STATUS (status);
+	case AML_LOR_OP:                 /* LOr (Operand0, Operand1) */
+
+		if (operand0 || operand1) {
+			return (TRUE);
+		}
+		break;
+	}
+
+	return (FALSE);
 }
+
+

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