psparse.c

来自「linux 内核源代码」· C语言 代码 · 共 676 行 · 第 1/2 页

C
676
字号
	case AE_CTRL_TERMINATE:		/*		 * A control method was terminated via a RETURN statement.		 * The walk of this method is complete.		 */		parser_state->aml = parser_state->aml_end;		status = AE_CTRL_TERMINATE;		break;	case AE_CTRL_BREAK:		parser_state->aml = walk_state->aml_last_while;		walk_state->control_state->common.value = FALSE;		status = acpi_ds_result_stack_pop(walk_state);		if (ACPI_SUCCESS(status)) {			status = AE_CTRL_BREAK;		}		break;	case AE_CTRL_CONTINUE:		parser_state->aml = walk_state->aml_last_while;		status = acpi_ds_result_stack_pop(walk_state);		if (ACPI_SUCCESS(status)) {			status = AE_CTRL_CONTINUE;		}		break;	case AE_CTRL_PENDING:		parser_state->aml = walk_state->aml_last_while;		break;#if 0	case AE_CTRL_SKIP:		parser_state->aml = parser_state->scope->parse_scope.pkg_end;		status = AE_OK;		break;#endif	case AE_CTRL_TRUE:		/*		 * Predicate of an IF was true, and we are at the matching ELSE.		 * Just close out this package		 */		parser_state->aml = acpi_ps_get_next_package_end(parser_state);		status = acpi_ds_result_stack_pop(walk_state);		if (ACPI_SUCCESS(status)) {			status = AE_CTRL_PENDING;		}		break;	case AE_CTRL_FALSE:		/*		 * Either an IF/WHILE Predicate was false or we encountered a BREAK		 * opcode.  In both cases, we do not execute the rest of the		 * package;  We simply close out the parent (finishing the walk of		 * this branch of the tree) and continue execution at the parent		 * level.		 */		parser_state->aml = parser_state->scope->parse_scope.pkg_end;		/* In the case of a BREAK, just force a predicate (if any) to FALSE */		walk_state->control_state->common.value = FALSE;		status = AE_CTRL_END;		break;	case AE_CTRL_TRANSFER:		/* A method call (invocation) -- transfer control */		status = AE_CTRL_TRANSFER;		walk_state->prev_op = op;		walk_state->method_call_op = op;		walk_state->method_call_node =		    (op->common.value.arg)->common.node;		/* Will return value (if any) be used by the caller? */		walk_state->return_used =		    acpi_ds_is_result_used(op, walk_state);		break;	default:		status = callback_status;		if ((callback_status & AE_CODE_MASK) == AE_CODE_CONTROL) {			status = AE_OK;		}		break;	}	return_ACPI_STATUS(status);}/******************************************************************************* * * FUNCTION:    acpi_ps_parse_aml * * PARAMETERS:  walk_state      - Current state * * * RETURN:      Status * * DESCRIPTION: Parse raw AML and return a tree of ops * ******************************************************************************/acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state){	acpi_status status;	struct acpi_thread_state *thread;	struct acpi_thread_state *prev_walk_list = acpi_gbl_current_walk_list;	struct acpi_walk_state *previous_walk_state;	ACPI_FUNCTION_TRACE(ps_parse_aml);	ACPI_DEBUG_PRINT((ACPI_DB_PARSE,			  "Entered with WalkState=%p Aml=%p size=%X\n",			  walk_state, walk_state->parser_state.aml,			  walk_state->parser_state.aml_size));	/* Create and initialize a new thread state */	thread = acpi_ut_create_thread_state();	if (!thread) {		acpi_ds_delete_walk_state(walk_state);		return_ACPI_STATUS(AE_NO_MEMORY);	}	walk_state->thread = thread;	/*	 * If executing a method, the starting sync_level is this method's	 * sync_level	 */	if (walk_state->method_desc) {		walk_state->thread->current_sync_level =		    walk_state->method_desc->method.sync_level;	}	acpi_ds_push_walk_state(walk_state, thread);	/*	 * This global allows the AML debugger to get a handle to the currently	 * executing control method.	 */	acpi_gbl_current_walk_list = thread;	/*	 * Execute the walk loop as long as there is a valid Walk State.  This	 * handles nested control method invocations without recursion.	 */	ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "State=%p\n", walk_state));	status = AE_OK;	while (walk_state) {		if (ACPI_SUCCESS(status)) {			/*			 * The parse_loop executes AML until the method terminates			 * or calls another method.			 */			status = acpi_ps_parse_loop(walk_state);		}		ACPI_DEBUG_PRINT((ACPI_DB_PARSE,				  "Completed one call to walk loop, %s State=%p\n",				  acpi_format_exception(status), walk_state));		if (status == AE_CTRL_TRANSFER) {			/*			 * A method call was detected.			 * Transfer control to the called control method			 */			status =			    acpi_ds_call_control_method(thread, walk_state,							NULL);			if (ACPI_FAILURE(status)) {				status =				    acpi_ds_method_error(status, walk_state);			}			/*			 * If the transfer to the new method method call worked, a new walk			 * state was created -- get it			 */			walk_state = acpi_ds_get_current_walk_state(thread);			continue;		} else if (status == AE_CTRL_TERMINATE) {			status = AE_OK;		} else if ((status != AE_OK) && (walk_state->method_desc)) {			/* Either the method parse or actual execution failed */			ACPI_ERROR_METHOD("Method parse/execution failed",					  walk_state->method_node, NULL,					  status);			/* Check for possible multi-thread reentrancy problem */			if ((status == AE_ALREADY_EXISTS) &&			    (!walk_state->method_desc->method.mutex)) {				ACPI_INFO((AE_INFO,					   "Marking method %4.4s as Serialized",					   walk_state->method_node->name.					   ascii));				/*				 * Method tried to create an object twice. The probable cause is				 * that the method cannot handle reentrancy.				 *				 * The method is marked not_serialized, but it tried to create				 * a named object, causing the second thread entrance to fail.				 * Workaround this problem by marking the method permanently				 * as Serialized.				 */				walk_state->method_desc->method.method_flags |=				    AML_METHOD_SERIALIZED;				walk_state->method_desc->method.sync_level = 0;			}		}		/* We are done with this walk, move on to the parent if any */		walk_state = acpi_ds_pop_walk_state(thread);		/* Reset the current scope to the beginning of scope stack */		acpi_ds_scope_stack_clear(walk_state);		/*		 * If we just returned from the execution of a control method or if we		 * encountered an error during the method parse phase, there's lots of		 * cleanup to do		 */		if (((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) ==		     ACPI_PARSE_EXECUTE) || (ACPI_FAILURE(status))) {			acpi_ds_terminate_control_method(walk_state->							 method_desc,							 walk_state);		}		/* Delete this walk state and all linked control states */		acpi_ps_cleanup_scope(&walk_state->parser_state);		previous_walk_state = walk_state;		ACPI_DEBUG_PRINT((ACPI_DB_PARSE,				  "ReturnValue=%p, ImplicitValue=%p State=%p\n",				  walk_state->return_desc,				  walk_state->implicit_return_obj, walk_state));		/* Check if we have restarted a preempted walk */		walk_state = acpi_ds_get_current_walk_state(thread);		if (walk_state) {			if (ACPI_SUCCESS(status)) {				/*				 * There is another walk state, restart it.				 * If the method return value is not used by the parent,				 * The object is deleted				 */				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;				}			} else {				/* On error, delete any return object */				acpi_ut_remove_reference(previous_walk_state->							 return_desc);			}		}		/*		 * Just completed a 1st-level method, save the final internal return		 * value (if any)		 */		else if (previous_walk_state->caller_return_desc) {			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 */				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);	}	/* Normal exit */	acpi_ex_release_all_mutexes(thread);	acpi_ut_delete_generic_state(ACPI_CAST_PTR				     (union acpi_generic_state, thread));	acpi_gbl_current_walk_list = prev_walk_list;	return_ACPI_STATUS(status);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?