⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exfldio.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************** * * Module Name: exfldio - Aml Field I/O * *****************************************************************************//* * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions, and the following disclaimer, *    without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer *    substantially similar to the "NO WARRANTY" disclaimer below *    ("Disclaimer") and any redistribution must be conditioned upon *    including a substantially similar Disclaimer requirement for further *    binary redistribution. * 3. Neither the names of the above-listed copyright holders nor the names *    of any contributors may be used to endorse or promote products derived *    from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. */#include <acpi/acpi.h>#include <acpi/acinterp.h>#include <acpi/amlcode.h>#include <acpi/acevents.h>#include <acpi/acdispat.h>#define _COMPONENT          ACPI_EXECUTERACPI_MODULE_NAME("exfldio")/* Local prototypes */static acpi_statusacpi_ex_field_datum_io(union acpi_operand_object *obj_desc,		       u32 field_datum_byte_offset,		       acpi_integer * value, u32 read_write);static u8acpi_ex_register_overflow(union acpi_operand_object *obj_desc,			  acpi_integer value);static acpi_statusacpi_ex_setup_region(union acpi_operand_object *obj_desc,		     u32 field_datum_byte_offset);/******************************************************************************* * * 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 Region if necessary and *              validate the request. * ******************************************************************************/static acpi_statusacpi_ex_setup_region(union acpi_operand_object *obj_desc,		     u32 field_datum_byte_offset){	acpi_status status = AE_OK;	union acpi_operand_object *rgn_desc;	ACPI_FUNCTION_TRACE_U32("ex_setup_region", field_datum_byte_offset);	rgn_desc = obj_desc->common_field.region_obj;	/* We must have a valid region */	if (ACPI_GET_OBJECT_TYPE(rgn_desc) != ACPI_TYPE_REGION) {		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,				  "Needed Region, found type %X (%s)\n",				  ACPI_GET_OBJECT_TYPE(rgn_desc),				  acpi_ut_get_object_type_name(rgn_desc)));		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->common.flags & AOPOBJ_DATA_VALID)) {		status = acpi_ds_get_region_arguments(rgn_desc);		if (ACPI_FAILURE(status)) {			return_ACPI_STATUS(status);		}	}	if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) {		/* SMBus has a non-linear address space */		return_ACPI_STATUS(AE_OK);	}#ifdef ACPI_UNDER_DEVELOPMENT	/*	 * If the Field access is any_acc, we can now compute the optimal	 * access (because we know know the length of the parent region)	 */	if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {		if (ACPI_FAILURE(status)) {			return_ACPI_STATUS(status);		}	}#endif	/*	 * 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 (acpi_gbl_enable_interpreter_slack) {			/*			 * Slack mode only:  We will go ahead and allow access to this			 * field if it is within the region length rounded up to the next			 * access width boundary.			 */			if (ACPI_ROUND_UP(rgn_desc->region.length,					  obj_desc->common_field.					  access_byte_width) >=			    (obj_desc->common_field.base_byte_offset +			     (acpi_native_uint) obj_desc->common_field.			     access_byte_width + field_datum_byte_offset)) {				return_ACPI_STATUS(AE_OK);			}		}		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",					  acpi_ut_get_node_name(obj_desc->								common_field.								node),					  obj_desc->common_field.					  access_byte_width,					  acpi_ut_get_node_name(rgn_desc->								region.node),					  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",				  acpi_ut_get_node_name(obj_desc->common_field.							node),				  obj_desc->common_field.base_byte_offset,				  field_datum_byte_offset,				  obj_desc->common_field.access_byte_width,				  acpi_ut_get_node_name(rgn_desc->region.node),				  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 at least *                                        the size of acpi_integer) *              Function                - Read or Write flag plus other region- *                                        dependent flags * * RETURN:      Status * * DESCRIPTION: Read or Write a single field datum to an Operation Region. * ******************************************************************************/acpi_statusacpi_ex_access_region(union acpi_operand_object *obj_desc,		      u32 field_datum_byte_offset,		      acpi_integer * value, u32 function){	acpi_status status;	union acpi_operand_object *rgn_desc;	acpi_physical_address address;	ACPI_FUNCTION_TRACE("ex_access_region");	/*	 * Ensure that the region operands are fully evaluated and verify	 * the validity of the request	 */	status = acpi_ex_setup_region(obj_desc, field_datum_byte_offset);	if (ACPI_FAILURE(status)) {		return_ACPI_STATUS(status);	}	/*	 * 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 ((function & ACPI_IO_MASK) == 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], Width %X, byte_base %X, Offset %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_FORMAT_UINT64(address)));	/* Invoke the appropriate address_space/op_region handler */	status = acpi_ev_address_space_dispatch(rgn_desc, function,						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_REPORT_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. * ******************************************************************************/static u8acpi_ex_register_overflow(union 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) * ******************************************************************************/static acpi_statusacpi_ex_field_datum_io(union 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;			/* To support reads without saving return value */			value = &local_value;		}		/* Clear the entire return buffer first, [Very Important!] */		*value = 0;	}	/*	 * The four types of fields are:	 *	 * buffer_field - Read/write from/to a Buffer	 * region_field - Read/write from/to a Operation Region.	 * bank_field  - Write to a Bank Register, then read/write from/to an	 *               operation_region	 * index_field - Write to an Index Register, then read/write from/to a	 *               Data Register	 */	switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {	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 ACPI_TYPE_LOCAL_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,					      (acpi_integer) 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.		 */

⌨️ 快捷键说明

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