static acpi_status
acpi_ds_init_buffer_field(u16 aml_opcode,
			  union acpi_operand_object *obj_desc,
			  union acpi_operand_object *buffer_desc,
			  union acpi_operand_object *offset_desc,
			  union acpi_operand_object *length_desc,
			  union acpi_operand_object *result_desc)
{
	u32 offset;
	u32 bit_offset;
	u32 bit_count;
	u8 field_flags;
	acpi_status status;

	ACPI_FUNCTION_TRACE_PTR(ds_init_buffer_field, obj_desc);

	/* Host object must be a Buffer */

	if (buffer_desc->common.type != ACPI_TYPE_BUFFER) {
		ACPI_ERROR((AE_INFO,
			    "Target of Create Field is not a Buffer object - %s",
			    acpi_ut_get_object_type_name(buffer_desc)));

		status = AE_AML_OPERAND_TYPE;
		goto cleanup;
	}

	/*
	 * The last parameter to all of these opcodes (result_desc) started
	 * out as a name_string, and should therefore now be a NS node
	 * after resolution in acpi_ex_resolve_operands().
	 */
	if (ACPI_GET_DESCRIPTOR_TYPE(result_desc) != ACPI_DESC_TYPE_NAMED) {
		ACPI_ERROR((AE_INFO,
			    "(%s) destination not a NS Node [%s]",
			    acpi_ps_get_opcode_name(aml_opcode),
			    acpi_ut_get_descriptor_name(result_desc)));

		status = AE_AML_OPERAND_TYPE;
		goto cleanup;
	}

	offset = (u32) offset_desc->integer.value;

	/*
	 * Setup the Bit offsets and counts, according to the opcode
	 */
	switch (aml_opcode) {
	case AML_CREATE_FIELD_OP:

		/* Offset is in bits, count is in bits */

		field_flags = AML_FIELD_ACCESS_BYTE;
		bit_offset = offset;
		bit_count = (u32) length_desc->integer.value;

		/* Must have a valid (>0) bit count */

		if (bit_count == 0) {
			ACPI_ERROR((AE_INFO,
				    "Attempt to CreateField of length zero"));
			status = AE_AML_OPERAND_VALUE;
			goto cleanup;
		}
		break;

	case AML_CREATE_BIT_FIELD_OP:

		/* Offset is in bits, Field is one bit */

		bit_offset = offset;
		bit_count = 1;
		field_flags = AML_FIELD_ACCESS_BYTE;
		break;

	case AML_CREATE_BYTE_FIELD_OP:

		/* Offset is in bytes, field is one byte */

		bit_offset = 8 * offset;
		bit_count = 8;
		field_flags = AML_FIELD_ACCESS_BYTE;
		break;

	case AML_CREATE_WORD_FIELD_OP:

		/* Offset is in bytes, field is one word */

		bit_offset = 8 * offset;
		bit_count = 16;
		field_flags = AML_FIELD_ACCESS_WORD;
		break;

	case AML_CREATE_DWORD_FIELD_OP:

		/* Offset is in bytes, field is one dword */

		bit_offset = 8 * offset;
		bit_count = 32;
		field_flags = AML_FIELD_ACCESS_DWORD;
		break;

	case AML_CREATE_QWORD_FIELD_OP:

		/* Offset is in bytes, field is one qword */

		bit_offset = 8 * offset;
		bit_count = 64;
		field_flags = AML_FIELD_ACCESS_QWORD;
		break;

	default:

		ACPI_ERROR((AE_INFO,
			    "Unknown field creation opcode 0x%02X",
			    aml_opcode));
		status = AE_AML_BAD_OPCODE;
		goto cleanup;
	}

	/* Entire field must fit within the current length of the buffer */

	if ((bit_offset + bit_count) > (8 * (u32) buffer_desc->buffer.length)) {
		ACPI_ERROR((AE_INFO,
			    "Field [%4.4s] at %u exceeds Buffer [%4.4s] size %u (bits)",
			    acpi_ut_get_node_name(result_desc),
			    bit_offset + bit_count,
			    acpi_ut_get_node_name(buffer_desc->buffer.node),
			    8 * (u32) buffer_desc->buffer.length));
		status = AE_AML_BUFFER_LIMIT;
		goto cleanup;
	}

	/*
	 * Initialize areas of the field object that are common to all fields
	 * For field_flags, use LOCK_RULE = 0 (NO_LOCK),
	 * UPDATE_RULE = 0 (UPDATE_PRESERVE)
	 */
	status = acpi_ex_prep_common_field_object(obj_desc, field_flags, 0,
						  bit_offset, bit_count);
	if (ACPI_FAILURE(status)) {
		goto cleanup;
	}

	obj_desc->buffer_field.buffer_obj = buffer_desc;

	/* Reference count for buffer_desc inherits obj_desc count */

	buffer_desc->common.reference_count = (u16)
	    (buffer_desc->common.reference_count +
	     obj_desc->common.reference_count);

      cleanup:

	/* Always delete the operands */

	acpi_ut_remove_reference(offset_desc);
	acpi_ut_remove_reference(buffer_desc);

	if (aml_opcode == AML_CREATE_FIELD_OP) {
		acpi_ut_remove_reference(length_desc);
	}

	/* On failure, delete the result descriptor */

	if (ACPI_FAILURE(status)) {
		acpi_ut_remove_reference(result_desc);	/* Result descriptor */
	} else {
		/* Now the address and length are valid for this buffer_field */

		obj_desc->buffer_field.flags |= AOPOBJ_DATA_VALID;
	}

	return_ACPI_STATUS(status);
}
示例#2
0
acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
{
    union acpi_operand_object *obj_desc;
    union acpi_operand_object *second_desc = NULL;
    u32 type;
    acpi_status status;

    ACPI_FUNCTION_TRACE(ex_prep_field_value);



    if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) {
        if (!info->region_node) {
            ACPI_ERROR((AE_INFO, "Null RegionNode"));
            return_ACPI_STATUS(AE_AML_NO_OPERAND);
        }

        type = acpi_ns_get_type(info->region_node);
        if (type != ACPI_TYPE_REGION) {
            ACPI_ERROR((AE_INFO,
                        "Needed Region, found type %X (%s)",
                        type, acpi_ut_get_type_name(type)));

            return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
        }
    }



    obj_desc = acpi_ut_create_internal_object(info->field_type);
    if (!obj_desc) {
        return_ACPI_STATUS(AE_NO_MEMORY);
    }



    obj_desc->common_field.node = info->field_node;
    status = acpi_ex_prep_common_field_object(obj_desc, info->field_flags,
             info->attribute,
             info->field_bit_position,
             info->field_bit_length);
    if (ACPI_FAILURE(status)) {
        acpi_ut_delete_object_desc(obj_desc);
        return_ACPI_STATUS(status);
    }



    switch (info->field_type) {
    case ACPI_TYPE_LOCAL_REGION_FIELD:

        obj_desc->field.region_obj =
            acpi_ns_get_attached_object(info->region_node);



        acpi_ut_add_reference(obj_desc->field.region_obj);

        ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
                          "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n",
                          obj_desc->field.start_field_bit_offset,
                          obj_desc->field.base_byte_offset,
                          obj_desc->field.access_byte_width,
                          obj_desc->field.region_obj));
        break;

    case ACPI_TYPE_LOCAL_BANK_FIELD:

        obj_desc->bank_field.value = info->bank_value;
        obj_desc->bank_field.region_obj =
            acpi_ns_get_attached_object(info->region_node);
        obj_desc->bank_field.bank_obj =
            acpi_ns_get_attached_object(info->register_node);



        acpi_ut_add_reference(obj_desc->bank_field.region_obj);
        acpi_ut_add_reference(obj_desc->bank_field.bank_obj);

        ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
                          "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n",
                          obj_desc->bank_field.start_field_bit_offset,
                          obj_desc->bank_field.base_byte_offset,
                          obj_desc->field.access_byte_width,
                          obj_desc->bank_field.region_obj,
                          obj_desc->bank_field.bank_obj));


        second_desc = obj_desc->common.next_object;
        second_desc->extra.aml_start =
            ACPI_CAST_PTR(union acpi_parse_object,
                          info->data_register_node)->named.data;
        second_desc->extra.aml_length =
            ACPI_CAST_PTR(union acpi_parse_object,
                          info->data_register_node)->named.length;

        break;

    case ACPI_TYPE_LOCAL_INDEX_FIELD:



        obj_desc->index_field.index_obj =
            acpi_ns_get_attached_object(info->register_node);
        obj_desc->index_field.data_obj =
            acpi_ns_get_attached_object(info->data_register_node);

        if (!obj_desc->index_field.data_obj
                || !obj_desc->index_field.index_obj) {
            ACPI_ERROR((AE_INFO,
                        "Null Index Object during field prep"));
            acpi_ut_delete_object_desc(obj_desc);
            return_ACPI_STATUS(AE_AML_INTERNAL);
        }



        acpi_ut_add_reference(obj_desc->index_field.data_obj);
        acpi_ut_add_reference(obj_desc->index_field.index_obj);


        obj_desc->index_field.value =
            (u32) ACPI_ROUND_DOWN(ACPI_DIV_8(info->field_bit_position),
                                  obj_desc->index_field.
                                  access_byte_width);

        ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
                          "IndexField: BitOff %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n",
                          obj_desc->index_field.start_field_bit_offset,
                          obj_desc->index_field.base_byte_offset,
                          obj_desc->index_field.value,
                          obj_desc->field.access_byte_width,
                          obj_desc->index_field.index_obj,
                          obj_desc->index_field.data_obj));
        break;

    default:

        break;
    }


    status = acpi_ns_attach_object(info->field_node, obj_desc,
                                   acpi_ns_get_type(info->field_node));

    ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
                      "Set NamedObj %p [%4.4s], ObjDesc %p\n",
                      info->field_node,
                      acpi_ut_get_node_name(info->field_node), obj_desc));



    acpi_ut_remove_reference(obj_desc);
    return_ACPI_STATUS(status);
}