exfldio.c

来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 1,014 行 · 第 1/2 页

C
1,014
字号
/****************************************************************************** * * Module Name: exfldio - Aml Field I/O *              $Revision: 84 $ * *****************************************************************************//* *  Copyright (C) 2000 - 2002, 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 "acinterp.h"#include "amlcode.h"#include "acnamesp.h"#include "achware.h"#include "acevents.h"#include "acdispat.h"#define _COMPONENT          ACPI_EXECUTER	 ACPI_MODULE_NAME    ("exfldio")/******************************************************************************* * * FUNCTION:    Acpi_ex_setup_region * * PARAMETERS:  *Obj_desc               - Field to be read or written *              Field_datum_byte_offset - Byte offset of this datum within the *                                        parent field * * RETURN:      Status * * DESCRIPTION: Common processing for Acpi_ex_extract_from_field and *              Acpi_ex_insert_into_field. Initialize the * ******************************************************************************/acpi_statusacpi_ex_setup_region (	acpi_operand_object     *obj_desc,	u32                     field_datum_byte_offset){	acpi_status             status = AE_OK;	acpi_operand_object     *rgn_desc;	ACPI_FUNCTION_TRACE_U32 ("Ex_setup_region", field_datum_byte_offset);	rgn_desc = obj_desc->common_field.region_obj;	if (ACPI_TYPE_REGION != rgn_desc->common.type) {		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %x %s\n",			rgn_desc->common.type, acpi_ut_get_type_name (rgn_desc->common.type)));		return_ACPI_STATUS (AE_AML_OPERAND_TYPE);	}	/*	 * If the Region Address and Length have not been previously evaluated,	 * evaluate them now and save the results.	 */	if (!(rgn_desc->region.flags & AOPOBJ_DATA_VALID)) {		status = acpi_ds_get_region_arguments (rgn_desc);		if (ACPI_FAILURE (status)) {			return_ACPI_STATUS (status);		}	}	/*	 * Validate the request.  The entire request from the byte offset for a	 * length of one field datum (access width) must fit within the region.	 * (Region length is specified in bytes)	 */	if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset			   + field_datum_byte_offset			   + obj_desc->common_field.access_byte_width)) {		if (rgn_desc->region.length < obj_desc->common_field.access_byte_width) {			/*			 * This is the case where the Access_type (Acc_word, etc.) is wider			 * than the region itself.  For example, a region of length one			 * byte, and a field with Dword access specified.			 */			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,				"Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n",				(char *) &obj_desc->common_field.node->name, obj_desc->common_field.access_byte_width,				(char *) &rgn_desc->region.node->name, rgn_desc->region.length));		}		/*		 * Offset rounded up to next multiple of field width		 * exceeds region length, indicate an error		 */		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,			"Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n",			(char *) &obj_desc->common_field.node->name, obj_desc->common_field.base_byte_offset,			field_datum_byte_offset, obj_desc->common_field.access_byte_width,			(char *) &rgn_desc->region.node->name, rgn_desc->region.length));		return_ACPI_STATUS (AE_AML_REGION_LIMIT);	}	return_ACPI_STATUS (AE_OK);}/******************************************************************************* * * FUNCTION:    Acpi_ex_access_region * * PARAMETERS:  *Obj_desc               - Field to be read *              Field_datum_byte_offset - Byte offset of this datum within the *                                        parent field *              *Value                  - Where to store value (must be 32 bits) *              Read_write              - Read or Write flag * * RETURN:      Status * * DESCRIPTION: Read or Write a single field datum to an Operation Region. * ******************************************************************************/acpi_statusacpi_ex_access_region (	acpi_operand_object     *obj_desc,	u32                     field_datum_byte_offset,	acpi_integer            *value,	u32                     read_write){	acpi_status             status;	acpi_operand_object     *rgn_desc;	ACPI_PHYSICAL_ADDRESS   address;	ACPI_FUNCTION_TRACE ("Ex_access_region");	/*	 * The physical address of this field datum is:	 *	 * 1) The base of the region, plus	 * 2) The base offset of the field, plus	 * 3) The current offset into the field	 */	rgn_desc = obj_desc->common_field.region_obj;	address = rgn_desc->region.address			 + obj_desc->common_field.base_byte_offset			 + field_datum_byte_offset;	if (read_write == ACPI_READ) {		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));	}	else {		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));	}	ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,		" Region[%s-%X] Access %X Base:Off %X:%X at %8.8X%8.8X\n",		acpi_ut_get_region_name (rgn_desc->region.space_id),		rgn_desc->region.space_id,		obj_desc->common_field.access_byte_width,		obj_desc->common_field.base_byte_offset,		field_datum_byte_offset,		ACPI_HIDWORD (address), ACPI_LODWORD (address)));	/* Invoke the appropriate Address_space/Op_region handler */	status = acpi_ev_address_space_dispatch (rgn_desc, read_write,			  address, ACPI_MUL_8 (obj_desc->common_field.access_byte_width), value);	if (ACPI_FAILURE (status)) {		if (status == AE_NOT_IMPLEMENTED) {			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,				"Region %s(%X) not implemented\n",				acpi_ut_get_region_name (rgn_desc->region.space_id),				rgn_desc->region.space_id));		}		else if (status == AE_NOT_EXIST) {			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,				"Region %s(%X) has no handler\n",				acpi_ut_get_region_name (rgn_desc->region.space_id),				rgn_desc->region.space_id));		}	}	return_ACPI_STATUS (status);}/******************************************************************************* * * FUNCTION:    Acpi_ex_register_overflow * * PARAMETERS:  *Obj_desc               - Register(Field) to be written *              Value                   - Value to be stored * * RETURN:      TRUE if value overflows the field, FALSE otherwise * * DESCRIPTION: Check if a value is out of range of the field being written. *              Used to check if the values written to Index and Bank registers *              are out of range.  Normally, the value is simply truncated *              to fit the field, but this case is most likely a serious *              coding error in the ASL. * ******************************************************************************/u8acpi_ex_register_overflow (	acpi_operand_object     *obj_desc,	acpi_integer            value){	if (obj_desc->common_field.bit_length >= ACPI_INTEGER_BIT_SIZE) {		/*		 * The field is large enough to hold the maximum integer, so we can		 * never overflow it.		 */		return (FALSE);	}	if (value >= (acpi_integer) (1 << obj_desc->common_field.bit_length)) {		/*		 * The Value is larger than the maximum value that can fit into		 * the register.		 */		return (TRUE);	}	/* The Value will fit into the field with no truncation */	return (FALSE);}/******************************************************************************* * * FUNCTION:    Acpi_ex_field_datum_io * * PARAMETERS:  *Obj_desc               - Field to be read *              Field_datum_byte_offset - Byte offset of this datum within the *                                        parent field *              *Value                  - Where to store value (must be 64 bits) *              Read_write              - Read or Write flag * * RETURN:      Status * * DESCRIPTION: Read or Write a single datum of a field.  The Field_type is *              demultiplexed here to handle the different types of fields *              (Buffer_field, Region_field, Index_field, Bank_field) * ******************************************************************************/acpi_statusacpi_ex_field_datum_io (	acpi_operand_object     *obj_desc,	u32                     field_datum_byte_offset,	acpi_integer            *value,	u32                     read_write){	acpi_status             status;	acpi_integer            local_value;	ACPI_FUNCTION_TRACE_U32 ("Ex_field_datum_io", field_datum_byte_offset);	if (read_write == ACPI_READ) {		if (!value) {			local_value = 0;			value = &local_value; /* To support reads without saving return value */		}		/* Clear the entire return buffer first, [Very Important!] */		*value = 0;	}	/*	 * The four types of fields are:	 *	 * Buffer_fields - Read/write from/to a Buffer	 * Region_fields - Read/write from/to a Operation Region.	 * Bank_fields  - Write to a Bank Register, then read/write from/to an Op_region	 * Index_fields - Write to an Index Register, then read/write from/to a Data Register	 */	switch (obj_desc->common.type) {	case ACPI_TYPE_BUFFER_FIELD:		/*		 * If the Buffer_field arguments have not been previously evaluated,		 * evaluate them now and save the results.		 */		if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {			status = acpi_ds_get_buffer_field_arguments (obj_desc);			if (ACPI_FAILURE (status)) {				return_ACPI_STATUS (status);			}		}		if (read_write == ACPI_READ) {			/*			 * Copy the data from the source buffer.			 * Length is the field width in bytes.			 */			ACPI_MEMCPY (value, (obj_desc->buffer_field.buffer_obj)->buffer.pointer					  + obj_desc->buffer_field.base_byte_offset					  + field_datum_byte_offset,					  obj_desc->common_field.access_byte_width);		}		else {			/*			 * Copy the data to the target buffer.			 * Length is the field width in bytes.			 */			ACPI_MEMCPY ((obj_desc->buffer_field.buffer_obj)->buffer.pointer					+ obj_desc->buffer_field.base_byte_offset					+ field_datum_byte_offset,					value, obj_desc->common_field.access_byte_width);		}		status = AE_OK;		break;	case INTERNAL_TYPE_BANK_FIELD:		/* Ensure that the Bank_value is not beyond the capacity of the register */		if (acpi_ex_register_overflow (obj_desc->bank_field.bank_obj,				  obj_desc->bank_field.value)) {			return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);		}		/*		 * For Bank_fields, we must write the Bank_value to the Bank_register		 * (itself a Region_field) before we can access the data.		 */		status = acpi_ex_insert_into_field (obj_desc->bank_field.bank_obj,				 &obj_desc->bank_field.value,				 sizeof (obj_desc->bank_field.value));		if (ACPI_FAILURE (status)) {			return_ACPI_STATUS (status);		}		/*		 * Now that the Bank has been selected, fall through to the		 * Region_field case and write the datum to the Operation Region		 */		/* No break; ! */	case INTERNAL_TYPE_REGION_FIELD:		/*		 * For simple Region_fields, we just directly access the owning		 * Operation Region.		 */		status = acpi_ex_setup_region (obj_desc, field_datum_byte_offset);		if (ACPI_FAILURE (status)) {			return_ACPI_STATUS (status);		}		status = acpi_ex_access_region (obj_desc, field_datum_byte_offset, value,				  read_write);		break;	case INTERNAL_TYPE_INDEX_FIELD:		/* Ensure that the Index_value is not beyond the capacity of the register */		if (acpi_ex_register_overflow (obj_desc->index_field.index_obj,				  obj_desc->index_field.value)) {			return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);		}		/* Write the index value to the Index_register (itself a Region_field) */		status = acpi_ex_insert_into_field (obj_desc->index_field.index_obj,				 &obj_desc->index_field.value,				 sizeof (obj_desc->index_field.value));		if (ACPI_FAILURE (status)) {			return_ACPI_STATUS (status);		}		if (read_write == ACPI_READ) {			/* Read the datum from the Data_register */			status = acpi_ex_extract_from_field (obj_desc->index_field.data_obj,					  value, obj_desc->common_field.access_byte_width);		}		else {			/* Write the datum to the Data register */			status = acpi_ex_insert_into_field (obj_desc->index_field.data_obj,					  value, obj_desc->common_field.access_byte_width);		}		break;	default:		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p, Wrong object type - %s\n",			obj_desc, acpi_ut_get_type_name (obj_desc->common.type)));		status = AE_AML_INTERNAL;		break;	}	if (ACPI_SUCCESS (status)) {		if (read_write == ACPI_READ) {			ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read=%8.8X%8.8X\n",					   ACPI_HIDWORD (*value), ACPI_LODWORD (*value)));		}		else {			ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written=%8.8X%8.8X\n",					   ACPI_HIDWORD (*value), ACPI_LODWORD (*value)));		}	}	return_ACPI_STATUS (status);}/******************************************************************************* * * FUNCTION:    Acpi_ex_write_with_update_rule * * PARAMETERS:  *Obj_desc           - Field to be set *              Value               - Value to store * * RETURN:      Status * * DESCRIPTION: Apply the field update rule to a field write * ******************************************************************************/acpi_statusacpi_ex_write_with_update_rule (	acpi_operand_object     *obj_desc,	acpi_integer            mask,	acpi_integer            field_value,	u32                     field_datum_byte_offset){	acpi_status             status = AE_OK;	acpi_integer            merged_value;	acpi_integer            current_value;	ACPI_FUNCTION_TRACE_U32 ("Ex_write_with_update_rule", mask);	/* Start with the new bits  */	merged_value = field_value;	/* If the mask is all ones, we don't need to worry about the update rule */	if (mask != ACPI_UINT32_MAX) {		/* Decode the update rule */		switch (obj_desc->common_field.field_flags & AML_FIELD_UPDATE_RULE_MASK) {		case AML_FIELD_UPDATE_PRESERVE:			/*			 * Check if update rule needs to be applied (not if mask is all			 * ones)  The left shift drops the bits we want to ignore.			 */			if ((~mask << (ACPI_MUL_8 (sizeof (mask)) -					 ACPI_MUL_8 (obj_desc->common_field.access_byte_width))) != 0) {				/*				 * Read the current contents of the byte/word/dword containing				 * the field, and merge with the new field value.				 */				status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset,						  &current_value, ACPI_READ);				merged_value |= (current_value & ~mask);			}			break;		case AML_FIELD_UPDATE_WRITE_AS_ONES:			/* Set positions outside the field to all ones */			merged_value |= ~mask;			break;		case AML_FIELD_UPDATE_WRITE_AS_ZEROS:			/* Set positions outside the field to all zeros */			merged_value &= mask;

⌨️ 快捷键说明

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