Пример #1
0
static ACPI_STATUS
AcpiDbTestFieldUnitType (
    ACPI_OPERAND_OBJECT     *ObjDesc)
{
    ACPI_OPERAND_OBJECT     *RegionObj;
    UINT32                  BitLength = 0;
    UINT32                  ByteLength = 0;
    ACPI_STATUS             Status = AE_OK;
    ACPI_OPERAND_OBJECT     *RetBufferDesc;


    /* Supported spaces are memory/io/pci_config */

    RegionObj = ObjDesc->Field.RegionObj;
    switch (RegionObj->Region.SpaceId)
    {
    case ACPI_ADR_SPACE_SYSTEM_MEMORY:
    case ACPI_ADR_SPACE_SYSTEM_IO:
    case ACPI_ADR_SPACE_PCI_CONFIG:

        /* Need the interpreter to execute */

        AcpiUtAcquireMutex (ACPI_MTX_INTERPRETER);
        AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);

        /* Exercise read-then-write */

        Status = AcpiExReadDataFromField (NULL, ObjDesc, &RetBufferDesc);
        if (Status == AE_OK)
        {
            AcpiExWriteDataToField (RetBufferDesc, ObjDesc, NULL);
            AcpiUtRemoveReference (RetBufferDesc);
        }

        AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
        AcpiUtReleaseMutex (ACPI_MTX_INTERPRETER);

        BitLength = ObjDesc->CommonField.BitLength;
        ByteLength = ACPI_ROUND_BITS_UP_TO_BYTES (BitLength);

        AcpiOsPrintf (ACPI_DEBUG_LENGTH_FORMAT " [%s]", BitLength,
            ByteLength, AcpiUtGetRegionName (RegionObj->Region.SpaceId));
        return (Status);

    default:

        AcpiOsPrintf (
            "      %s address space is not supported in this command [%4.4s]",
            AcpiUtGetRegionName (RegionObj->Region.SpaceId),
            RegionObj->Region.Node->Name.Ascii);
        return (AE_OK);
    }
}
Пример #2
0
static ACPI_STATUS
AcpiDbTestIntegerType (
    ACPI_NAMESPACE_NODE     *Node,
    UINT32                  BitLength)
{
    ACPI_OBJECT             *Temp1 = NULL;
    ACPI_OBJECT             *Temp2 = NULL;
    ACPI_OBJECT             *Temp3 = NULL;
    ACPI_OBJECT             WriteValue;
    UINT64                  ValueToWrite;
    ACPI_STATUS             Status;


    if (BitLength > 64)
    {
        AcpiOsPrintf (" Invalid length for an Integer: %u", BitLength);
        return (AE_OK);
    }

    /* Read the original value */

    Status = AcpiDbReadFromObject (Node, ACPI_TYPE_INTEGER, &Temp1);
    if (ACPI_FAILURE (Status))
    {
        return (Status);
    }

    AcpiOsPrintf (" (%4.4X/%3.3X) %8.8X%8.8X",
        BitLength, ACPI_ROUND_BITS_UP_TO_BYTES (BitLength),
        ACPI_FORMAT_UINT64 (Temp1->Integer.Value));

    ValueToWrite = ACPI_UINT64_MAX >> (64 - BitLength);
    if (Temp1->Integer.Value == ValueToWrite)
    {
        ValueToWrite = 0;
    }

    /* Write a new value */

    WriteValue.Type = ACPI_TYPE_INTEGER;
    WriteValue.Integer.Value = ValueToWrite;
    Status = AcpiDbWriteToObject (Node, &WriteValue);
    if (ACPI_FAILURE (Status))
    {
        goto Exit;
    }

    /* Ensure that we can read back the new value */

    Status = AcpiDbReadFromObject (Node, ACPI_TYPE_INTEGER, &Temp2);
    if (ACPI_FAILURE (Status))
    {
        goto Exit;
    }

    if (Temp2->Integer.Value != ValueToWrite)
    {
        AcpiOsPrintf (" MISMATCH 2: %8.8X%8.8X, expecting %8.8X%8.8X",
            ACPI_FORMAT_UINT64 (Temp2->Integer.Value),
            ACPI_FORMAT_UINT64 (ValueToWrite));
    }

    /* Write back the original value */

    WriteValue.Integer.Value = Temp1->Integer.Value;
    Status = AcpiDbWriteToObject (Node, &WriteValue);
    if (ACPI_FAILURE (Status))
    {
        goto Exit;
    }

    /* Ensure that we can read back the original value */

    Status = AcpiDbReadFromObject (Node, ACPI_TYPE_INTEGER, &Temp3);
    if (ACPI_FAILURE (Status))
    {
        goto Exit;
    }

    if (Temp3->Integer.Value != Temp1->Integer.Value)
    {
        AcpiOsPrintf (" MISMATCH 3: %8.8X%8.8X, expecting %8.8X%8.8X",
            ACPI_FORMAT_UINT64 (Temp3->Integer.Value),
            ACPI_FORMAT_UINT64 (Temp1->Integer.Value));
    }

Exit:
    if (Temp1) {AcpiOsFree (Temp1);}
    if (Temp2) {AcpiOsFree (Temp2);}
    if (Temp3) {AcpiOsFree (Temp3);}
    return (AE_OK);
}
Пример #3
0
static ACPI_STATUS
AcpiDbTestOneObject (
    ACPI_HANDLE             ObjHandle,
    UINT32                  NestingLevel,
    void                    *Context,
    void                    **ReturnValue)
{
    ACPI_NAMESPACE_NODE     *Node;
    ACPI_OPERAND_OBJECT     *ObjDesc;
    ACPI_OPERAND_OBJECT     *RegionObj;
    ACPI_OBJECT_TYPE        LocalType;
    UINT32                  BitLength = 0;
    UINT32                  ByteLength = 0;
    ACPI_STATUS             Status = AE_OK;


    Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle);
    ObjDesc = Node->Object;

    /*
     * For the supported types, get the actual bit length or
     * byte length. Map the type to one of Integer/String/Buffer.
     */
    switch (Node->Type)
    {
    case ACPI_TYPE_INTEGER:

        /* Integer width is either 32 or 64 */

        LocalType = ACPI_TYPE_INTEGER;
        BitLength = AcpiGbl_IntegerBitWidth;
        break;

    case ACPI_TYPE_STRING:

        LocalType = ACPI_TYPE_STRING;
        ByteLength = ObjDesc->String.Length;
        break;

    case ACPI_TYPE_BUFFER:

        LocalType = ACPI_TYPE_BUFFER;
        ByteLength = ObjDesc->Buffer.Length;
        BitLength = ByteLength * 8;
        break;

    case ACPI_TYPE_FIELD_UNIT:
    case ACPI_TYPE_BUFFER_FIELD:
    case ACPI_TYPE_LOCAL_REGION_FIELD:
    case ACPI_TYPE_LOCAL_INDEX_FIELD:
    case ACPI_TYPE_LOCAL_BANK_FIELD:

        LocalType = ACPI_TYPE_INTEGER;
        if (ObjDesc)
        {
            /*
             * Returned object will be a Buffer if the field length
             * is larger than the size of an Integer (32 or 64 bits
             * depending on the DSDT version).
             */
            BitLength = ObjDesc->CommonField.BitLength;
            ByteLength = ACPI_ROUND_BITS_UP_TO_BYTES (BitLength);
            if (BitLength > AcpiGbl_IntegerBitWidth)
            {
                LocalType = ACPI_TYPE_BUFFER;
            }
        }
        break;

    default:

        /* Ignore all other types */

        return (AE_OK);
    }

    /* Emit the common prefix: Type:Name */

    AcpiOsPrintf ("%14s: %4.4s",
        AcpiUtGetTypeName (Node->Type), Node->Name.Ascii);
    if (!ObjDesc)
    {
        AcpiOsPrintf (" Ignoring, no attached object\n");
        return (AE_OK);
    }

    /*
     * Check for unsupported region types. Note: AcpiExec simulates
     * access to SystemMemory, SystemIO, PCI_Config, and EC.
     */
    switch (Node->Type)
    {
    case ACPI_TYPE_LOCAL_REGION_FIELD:

        RegionObj = ObjDesc->Field.RegionObj;
        switch (RegionObj->Region.SpaceId)
        {
        case ACPI_ADR_SPACE_SYSTEM_MEMORY:
        case ACPI_ADR_SPACE_SYSTEM_IO:
        case ACPI_ADR_SPACE_PCI_CONFIG:
        case ACPI_ADR_SPACE_EC:

            break;

        default:

            AcpiOsPrintf ("      %s space is not supported [%4.4s]\n",
                AcpiUtGetRegionName (RegionObj->Region.SpaceId),
                RegionObj->Region.Node->Name.Ascii);
            return (AE_OK);
        }
        break;

    default:
        break;
    }

    /* At this point, we have resolved the object to one of the major types */

    switch (LocalType)
    {
    case ACPI_TYPE_INTEGER:

        Status = AcpiDbTestIntegerType (Node, BitLength);
        break;

    case ACPI_TYPE_STRING:

        Status = AcpiDbTestStringType (Node, ByteLength);
        break;

    case ACPI_TYPE_BUFFER:

        Status = AcpiDbTestBufferType (Node, BitLength);
        break;

    default:

        AcpiOsPrintf (" Ignoring, type not implemented (%2.2X)",
            LocalType);
        break;
    }

    switch (Node->Type)
    {
    case ACPI_TYPE_LOCAL_REGION_FIELD:

        RegionObj = ObjDesc->Field.RegionObj;
        AcpiOsPrintf (" (%s)",
            AcpiUtGetRegionName (RegionObj->Region.SpaceId));
        break;

    default:
        break;
    }

    AcpiOsPrintf ("\n");
    return (Status);
}
Пример #4
0
acpi_status
acpi_ex_write_data_to_field (
	union acpi_operand_object       *source_desc,
	union acpi_operand_object       *obj_desc,
	union acpi_operand_object       **result_desc)
{
	acpi_status                     status;
	u32                             length;
	u32                             required_length;
	void                            *buffer;
	void                            *new_buffer;
	u8                              locked;
	union acpi_operand_object       *buffer_desc;


	ACPI_FUNCTION_TRACE_PTR ("ex_write_data_to_field", obj_desc);


	/* Parameter validation */

	if (!source_desc || !obj_desc) {
		return_ACPI_STATUS (AE_AML_NO_OPERAND);
	}

	if (ACPI_GET_OBJECT_TYPE (obj_desc) == 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);
			}
		}
	}
	else if ((ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_REGION_FIELD) &&
			 (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS)) {
		/*
		 * This is an SMBus write.  We will bypass the entire field mechanism
		 * and handoff the buffer directly to the handler.
		 *
		 * Source must be a buffer of sufficient size (ACPI_SMBUS_BUFFER_SIZE).
		 */
		if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_BUFFER) {
			ACPI_REPORT_ERROR (("SMBus write requires Buffer, found type %s\n",
				acpi_ut_get_object_type_name (source_desc)));
			return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
		}

		if (source_desc->buffer.length < ACPI_SMBUS_BUFFER_SIZE) {
			ACPI_REPORT_ERROR (("SMBus write requires Buffer of length %X, found length %X\n",
				ACPI_SMBUS_BUFFER_SIZE, source_desc->buffer.length));
			return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
		}

		buffer_desc = acpi_ut_create_buffer_object (ACPI_SMBUS_BUFFER_SIZE);
		if (!buffer_desc) {
			return_ACPI_STATUS (AE_NO_MEMORY);
		}

		buffer = buffer_desc->buffer.pointer;
		ACPI_MEMCPY (buffer, source_desc->buffer.pointer, ACPI_SMBUS_BUFFER_SIZE);

		/* Lock entire transaction if requested */

		locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags);

		/*
		 * Perform the write (returns status and perhaps data in the same buffer)
		 * Note: SMBus protocol type is passed in upper 16-bits of Function.
		 */
		status = acpi_ex_access_region (obj_desc, 0,
				  (acpi_integer *) buffer,
				  ACPI_WRITE | (obj_desc->field.attribute << 16));
		acpi_ex_release_global_lock (locked);

		*result_desc = buffer_desc;
		return_ACPI_STATUS (status);
	}

	/*
	 * Get a pointer to the data to be written
	 */
	switch (ACPI_GET_OBJECT_TYPE (source_desc)) {
	case ACPI_TYPE_INTEGER:
		buffer = &source_desc->integer.value;
		length = sizeof (source_desc->integer.value);
		break;

	case ACPI_TYPE_BUFFER:
		buffer = source_desc->buffer.pointer;
		length = source_desc->buffer.length;
		break;

	case ACPI_TYPE_STRING:
		buffer = source_desc->string.pointer;
		length = source_desc->string.length;
		break;

	default:
		return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
	}

	/*
	 * We must have a buffer that is at least as long as the field
	 * we are writing to.  This is because individual fields are
	 * indivisible and partial writes are not supported -- as per
	 * the ACPI specification.
	 */
	new_buffer = NULL;
	required_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length);

	if (length < required_length) {
		/* We need to create a new buffer */

		new_buffer = ACPI_MEM_CALLOCATE (required_length);
		if (!new_buffer) {
			return_ACPI_STATUS (AE_NO_MEMORY);
		}

		/*
		 * Copy the original data to the new buffer, starting
		 * at Byte zero.  All unused (upper) bytes of the
		 * buffer will be 0.
		 */
		ACPI_MEMCPY ((char *) new_buffer, (char *) buffer, length);
		buffer = new_buffer;
		length = required_length;
	}

	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
		"field_write [FROM]: Obj %p (%s:%X), Buf %p, byte_len %X\n",
		source_desc, acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (source_desc)),
		ACPI_GET_OBJECT_TYPE (source_desc), buffer, length));
	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
		"field_write [TO]:  Obj %p (%s:%X), bit_len %X, bit_off %X, byte_off %X\n",
		obj_desc, acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (obj_desc)),
		ACPI_GET_OBJECT_TYPE (obj_desc),
		obj_desc->common_field.bit_length,
		obj_desc->common_field.start_field_bit_offset,
		obj_desc->common_field.base_byte_offset));

	/* Lock entire transaction if requested */

	locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags);

	/* Write to the field */

	status = acpi_ex_insert_into_field (obj_desc, buffer, length);
	acpi_ex_release_global_lock (locked);

	/* Free temporary buffer if we used one */

	if (new_buffer) {
		ACPI_MEM_FREE (new_buffer);
	}

	return_ACPI_STATUS (status);
}
Пример #5
0
acpi_status
acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
			     union acpi_operand_object *obj_desc,
			     union acpi_operand_object **ret_buffer_desc)
{
	acpi_status status;
	union acpi_operand_object *buffer_desc;
	acpi_size length;
	void *buffer;
	u32 function;

	ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);

	

	if (!obj_desc) {
		return_ACPI_STATUS(AE_AML_NO_OPERAND);
	}
	if (!ret_buffer_desc) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
		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);
			}
		}
	} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
		   (obj_desc->field.region_obj->region.space_id ==
		    ACPI_ADR_SPACE_SMBUS
		    || obj_desc->field.region_obj->region.space_id ==
		    ACPI_ADR_SPACE_GSBUS
		    || obj_desc->field.region_obj->region.space_id ==
		    ACPI_ADR_SPACE_IPMI)) {
		if (obj_desc->field.region_obj->region.space_id ==
		    ACPI_ADR_SPACE_SMBUS) {
			length = ACPI_SMBUS_BUFFER_SIZE;
			function =
			    ACPI_READ | (obj_desc->field.attribute << 16);
		} else if (obj_desc->field.region_obj->region.space_id ==
			   ACPI_ADR_SPACE_GSBUS) {
			length = ACPI_GSBUS_BUFFER_SIZE;
			function =
			    ACPI_READ | (obj_desc->field.attribute << 16);
		} else {	

			length = ACPI_IPMI_BUFFER_SIZE;
			function = ACPI_READ;
		}

		buffer_desc = acpi_ut_create_buffer_object(length);
		if (!buffer_desc) {
			return_ACPI_STATUS(AE_NO_MEMORY);
		}

		

		acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);

		

		status = acpi_ex_access_region(obj_desc, 0,
					       ACPI_CAST_PTR(u64,
							     buffer_desc->
							     buffer.pointer),
					       function);
		acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
		goto exit;
	}

	length =
	    (acpi_size) ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length);
	if (length > acpi_gbl_integer_byte_width) {

		

		buffer_desc = acpi_ut_create_buffer_object(length);
		if (!buffer_desc) {
			return_ACPI_STATUS(AE_NO_MEMORY);
		}
		buffer = buffer_desc->buffer.pointer;
	} else {
		

		buffer_desc = acpi_ut_create_integer_object((u64) 0);
		if (!buffer_desc) {
			return_ACPI_STATUS(AE_NO_MEMORY);
		}

		length = acpi_gbl_integer_byte_width;
		buffer = &buffer_desc->integer.value;
	}

	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
			  "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
			  obj_desc, obj_desc->common.type, buffer,
			  (u32) length));
	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
			  "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
			  obj_desc->common_field.bit_length,
			  obj_desc->common_field.start_field_bit_offset,
			  obj_desc->common_field.base_byte_offset));

	

	acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);

	

	status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length);
	acpi_ex_release_global_lock(obj_desc->common_field.field_flags);

      exit:
	if (ACPI_FAILURE(status)) {
		acpi_ut_remove_reference(buffer_desc);
	} else {
		*ret_buffer_desc = buffer_desc;
	}

	return_ACPI_STATUS(status);
}
Пример #6
0
ACPI_STATUS
AcpiExInsertIntoField (
    ACPI_OPERAND_OBJECT     *ObjDesc,
    void                    *Buffer,
    UINT32                  BufferLength)
{
    void                    *NewBuffer;
    ACPI_STATUS             Status;
    UINT64                  Mask;
    UINT64                  WidthMask;
    UINT64                  MergedDatum;
    UINT64                  RawDatum = 0;
    UINT32                  FieldOffset = 0;
    UINT32                  BufferOffset = 0;
    UINT32                  BufferTailBits;
    UINT32                  DatumCount;
    UINT32                  FieldDatumCount;
    UINT32                  AccessBitWidth;
    UINT32                  RequiredLength;
    UINT32                  i;


    ACPI_FUNCTION_TRACE (ExInsertIntoField);


    /* Validate input buffer */

    NewBuffer = NULL;
    RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES (
                        ObjDesc->CommonField.BitLength);
    /*
     * We must have a buffer that is at least as long as the field
     * we are writing to. This is because individual fields are
     * indivisible and partial writes are not supported -- as per
     * the ACPI specification.
     */
    if (BufferLength < RequiredLength)
    {
        /* We need to create a new buffer */

        NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength);
        if (!NewBuffer)
        {
            return_ACPI_STATUS (AE_NO_MEMORY);
        }

        /*
         * Copy the original data to the new buffer, starting
         * at Byte zero. All unused (upper) bytes of the
         * buffer will be 0.
         */
        memcpy ((char *) NewBuffer, (char *) Buffer, BufferLength);
        Buffer = NewBuffer;
        BufferLength = RequiredLength;
    }

/* TBD: Move to common setup code */

    /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */
    if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
    {
        ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
    }

    AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);

    /*
     * Create the bitmasks used for bit insertion.
     * Note: This if/else is used to bypass compiler differences with the
     * shift operator
     */
    if (AccessBitWidth == ACPI_INTEGER_BIT_SIZE)
    {
        WidthMask = ACPI_UINT64_MAX;
    }
    else
    {
        WidthMask = ACPI_MASK_BITS_ABOVE (AccessBitWidth);
    }

    Mask = WidthMask &
        ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);

    /* Compute the number of datums (access width data items) */

    DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength,
        AccessBitWidth);

    FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength +
        ObjDesc->CommonField.StartFieldBitOffset,
        AccessBitWidth);

    /* Get initial Datum from the input buffer */

    memcpy (&RawDatum, Buffer,
        ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
            BufferLength - BufferOffset));

    MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset;

    /* Write the entire field */

    for (i = 1; i < FieldDatumCount; i++)
    {
        /* Write merged datum to the target field */

        MergedDatum &= Mask;
        Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask,
                    MergedDatum, FieldOffset);
        if (ACPI_FAILURE (Status))
        {
            goto Exit;
        }

        FieldOffset += ObjDesc->CommonField.AccessByteWidth;

        /*
         * Start new output datum by merging with previous input datum
         * if necessary.
         *
         * Note: Before the shift, check if the shift value will be larger than
         * the integer size. If so, there is no need to perform the operation.
         * This avoids the differences in behavior between different compilers
         * concerning shift values larger than the target data width.
         */
        if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) <
            ACPI_INTEGER_BIT_SIZE)
        {
            MergedDatum = RawDatum >>
                (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
        }
        else
        {
Пример #7
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;
	acpi_status status;
	u32 access_byte_width;
	u32 type;

	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 0x%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);

		/*                                              */

		obj_desc->field.access_length = info->access_length;

		if (info->connection_node) {
			second_desc = info->connection_node->object;
			if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) {
				status =
				    acpi_ds_get_buffer_arguments(second_desc);
				if (ACPI_FAILURE(status)) {
					acpi_ut_delete_object_desc(obj_desc);
					return_ACPI_STATUS(status);
				}
			}

			obj_desc->field.resource_buffer =
			    second_desc->buffer.pointer;
			obj_desc->field.resource_length =
			    (u16)second_desc->buffer.length;
		} else if (info->resource_buffer) {
			obj_desc->field.resource_buffer = info->resource_buffer;
			obj_desc->field.resource_length = info->resource_length;
		}

		/*                                            */

		if ((obj_desc->field.region_obj->region.space_id ==
		     ACPI_ADR_SPACE_EC)
		    && (obj_desc->common_field.bit_length > 8)) {
			access_byte_width =
			    ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.
							bit_length);

			/*                                     */

			if (access_byte_width < 256) {
				obj_desc->common_field.access_byte_width =
				    (u8)access_byte_width;
			}
		}
		/*                                           */

		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);
}
Пример #8
0
acpi_status
acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
			   void *buffer, u32 buffer_length)
{
	acpi_status status;
	u64 raw_datum;
	u64 merged_datum;
	u32 field_offset = 0;
	u32 buffer_offset = 0;
	u32 buffer_tail_bits;
	u32 datum_count;
	u32 field_datum_count;
	u32 access_bit_width;
	u32 i;

	ACPI_FUNCTION_TRACE(ex_extract_from_field);

	/* Validate target buffer and clear it */

	if (buffer_length <
	    ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) {
		ACPI_ERROR((AE_INFO,
			    "Field size %u (bits) is too large for buffer (%u)",
			    obj_desc->common_field.bit_length, buffer_length));

		return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
	}

	ACPI_MEMSET(buffer, 0, buffer_length);
	access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width);

	/* Handle the simple case here */

	if ((obj_desc->common_field.start_field_bit_offset == 0) &&
	    (obj_desc->common_field.bit_length == access_bit_width)) {
		status = acpi_ex_field_datum_io(obj_desc, 0, buffer, ACPI_READ);
		return_ACPI_STATUS(status);
	}

/* TBD: Move to common setup code */

	/* Field algorithm is limited to sizeof(u64), truncate if needed */

	if (obj_desc->common_field.access_byte_width > sizeof(u64)) {
		obj_desc->common_field.access_byte_width = sizeof(u64);
		access_bit_width = sizeof(u64) * 8;
	}

	/* Compute the number of datums (access width data items) */

	datum_count =
	    ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
			     access_bit_width);

	field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
					     obj_desc->common_field.
					     start_field_bit_offset,
					     access_bit_width);

	/* Priming read from the field */

	status =
	    acpi_ex_field_datum_io(obj_desc, field_offset, &raw_datum,
				   ACPI_READ);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}
	merged_datum =
	    raw_datum >> obj_desc->common_field.start_field_bit_offset;

	/* Read the rest of the field */

	for (i = 1; i < field_datum_count; i++) {

		/* Get next input datum from the field */

		field_offset += obj_desc->common_field.access_byte_width;
		status = acpi_ex_field_datum_io(obj_desc, field_offset,
						&raw_datum, ACPI_READ);
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
		}

		/*
		 * Merge with previous datum if necessary.
		 *
		 * Note: Before the shift, check if the shift value will be larger than
		 * the integer size. If so, there is no need to perform the operation.
		 * This avoids the differences in behavior between different compilers
		 * concerning shift values larger than the target data width.
		 */
		if (access_bit_width -
		    obj_desc->common_field.start_field_bit_offset <
		    ACPI_INTEGER_BIT_SIZE) {
			merged_datum |=
			    raw_datum << (access_bit_width -
					  obj_desc->common_field.
					  start_field_bit_offset);
		}

		if (i == datum_count) {
			break;
		}

		/* Write merged datum to target buffer */

		ACPI_MEMCPY(((char *)buffer) + buffer_offset, &merged_datum,
			    ACPI_MIN(obj_desc->common_field.access_byte_width,
				     buffer_length - buffer_offset));

		buffer_offset += obj_desc->common_field.access_byte_width;
		merged_datum =
		    raw_datum >> obj_desc->common_field.start_field_bit_offset;
	}

	/* Mask off any extra bits in the last datum */

	buffer_tail_bits = obj_desc->common_field.bit_length % access_bit_width;
	if (buffer_tail_bits) {
		merged_datum &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits);
	}

	/* Write the last datum to the buffer */

	ACPI_MEMCPY(((char *)buffer) + buffer_offset, &merged_datum,
		    ACPI_MIN(obj_desc->common_field.access_byte_width,
			     buffer_length - buffer_offset));

	return_ACPI_STATUS(AE_OK);
}
Пример #9
0
acpi_status
acpi_ex_extract_from_field (
	union acpi_operand_object       *obj_desc,
	void                            *buffer,
	u32                             buffer_length)
{
	acpi_status                     status;
	u32                             field_datum_byte_offset;
	u32                             datum_offset;
	acpi_integer                    previous_raw_datum;
	acpi_integer                    this_raw_datum = 0;
	acpi_integer                    merged_datum = 0;
	u32                             byte_field_length;
	u32                             datum_count;


	ACPI_FUNCTION_TRACE ("ex_extract_from_field");


	/*
	 * The field must fit within the caller's buffer
	 */
	byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length);
	if (byte_field_length > buffer_length) {
		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
			"Field size %X (bytes) too large for buffer (%X)\n",
			byte_field_length, buffer_length));

		return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
	}

	/* Convert field byte count to datum count, round up if necessary */

	datum_count = ACPI_ROUND_UP_TO (byte_field_length,
			   obj_desc->common_field.access_byte_width);

	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
		"byte_len %X, datum_len %X, byte_gran %X\n",
		byte_field_length, datum_count,obj_desc->common_field.access_byte_width));

	/*
	 * Clear the caller's buffer (the whole buffer length as given)
	 * This is very important, especially in the cases where a byte is read,
	 * but the buffer is really a u32 (4 bytes).
	 */
	ACPI_MEMSET (buffer, 0, buffer_length);

	/* Read the first raw datum to prime the loop */

	field_datum_byte_offset = 0;
	datum_offset= 0;

	status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset,
			  &previous_raw_datum, ACPI_READ);
	if (ACPI_FAILURE (status)) {
		return_ACPI_STATUS (status);
	}


	/* We might actually be done if the request fits in one datum */

	if ((datum_count == 1) &&
		(obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM)) {
		/* 1) Shift the valid data bits down to start at bit 0 */

		merged_datum = (previous_raw_datum >> obj_desc->common_field.start_field_bit_offset);

		/* 2) Mask off any upper unused bits (bits not part of the field) */

		if (obj_desc->common_field.end_buffer_valid_bits) {
			merged_datum &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits);
		}

		/* Store the datum to the caller buffer */

		acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length,
				obj_desc->common_field.access_byte_width, datum_offset);

		return_ACPI_STATUS (AE_OK);
	}
Пример #10
0
ACPI_STATUS
AcpiExReadDataFromField (
    ACPI_WALK_STATE         *WalkState,
    ACPI_OPERAND_OBJECT     *ObjDesc,
    ACPI_OPERAND_OBJECT     **RetBufferDesc)
{
    ACPI_STATUS             Status;
    ACPI_OPERAND_OBJECT     *BufferDesc;
    ACPI_SIZE               Length;
    void                    *Buffer;
    UINT32                  Function;


    ACPI_FUNCTION_TRACE_PTR (ExReadDataFromField, ObjDesc);


    /* Parameter validation */

    if (!ObjDesc)
    {
        return_ACPI_STATUS (AE_AML_NO_OPERAND);
    }
    if (!RetBufferDesc)
    {
        return_ACPI_STATUS (AE_BAD_PARAMETER);
    }

    if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
    {
        /*
         * If the BufferField arguments have not been previously evaluated,
         * evaluate them now and save the results.
         */
        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
        {
            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
            if (ACPI_FAILURE (Status))
            {
                return_ACPI_STATUS (Status);
            }
        }
    }
    else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
             (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
    {
        /*
         * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold
         * the data and then directly access the region handler.
         *
         * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function
         */
        if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
        {
            Length = ACPI_SMBUS_BUFFER_SIZE;
            Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
        }
        else if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS)
        {
            Length = ACPI_GSBUS_BUFFER_SIZE;
            Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
        }
        else /* IPMI */
        {
            Length = ACPI_IPMI_BUFFER_SIZE;
            Function = ACPI_READ;
        }

        BufferDesc = AcpiUtCreateBufferObject (Length);
        if (!BufferDesc)
        {
            return_ACPI_STATUS (AE_NO_MEMORY);
        }

        /* Lock entire transaction if requested */

        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);

        /* Call the region handler for the read */

        Status = AcpiExAccessRegion (ObjDesc, 0,
                    ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer),
                    Function);
        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
        goto Exit;
    }

    /*
     * Allocate a buffer for the contents of the field.
     *
     * If the field is larger than the current integer width, create
     * a BUFFER to hold it.  Otherwise, use an INTEGER.  This allows
     * the use of arithmetic operators on the returned value if the
     * field size is equal or smaller than an Integer.
     *
     * Note: Field.length is in bits.
     */
    Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->Field.BitLength);
    if (Length > AcpiGbl_IntegerByteWidth)
    {
        /* Field is too large for an Integer, create a Buffer instead */

        BufferDesc = AcpiUtCreateBufferObject (Length);
        if (!BufferDesc)
        {
            return_ACPI_STATUS (AE_NO_MEMORY);
        }
        Buffer = BufferDesc->Buffer.Pointer;
    }
    else
    {
        /* Field will fit within an Integer (normal case) */

        BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0);
        if (!BufferDesc)
        {
            return_ACPI_STATUS (AE_NO_MEMORY);
        }

        Length = AcpiGbl_IntegerByteWidth;
        Buffer = &BufferDesc->Integer.Value;
    }

    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
        "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
        ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length));
    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
        "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
        ObjDesc->CommonField.BitLength,
        ObjDesc->CommonField.StartFieldBitOffset,
        ObjDesc->CommonField.BaseByteOffset));

    /* Lock entire transaction if requested */

    AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);

    /* Read from the field */

    Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length);
    AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);


Exit:
    if (ACPI_FAILURE (Status))
    {
        AcpiUtRemoveReference (BufferDesc);
    }
    else
    {
        *RetBufferDesc = BufferDesc;
    }

    return_ACPI_STATUS (Status);
}
Пример #11
0
/*******************************************************************************
 *
 * FUNCTION:    acpi_ex_read_data_from_field
 *
 * PARAMETERS:  walk_state          - Current execution state
 *              obj_desc            - The named field
 *              ret_buffer_desc     - Where the return data object is stored
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Read from a named field.  Returns either an Integer or a
 *              Buffer, depending on the size of the field.
 *
 ******************************************************************************/
acpi_status
acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
			     union acpi_operand_object *obj_desc,
			     union acpi_operand_object **ret_buffer_desc)
{
	acpi_status status;
	union acpi_operand_object *buffer_desc;
	acpi_size length;
	void *buffer;

	ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);

	/* Parameter validation */

	if (!obj_desc) {
		return_ACPI_STATUS(AE_AML_NO_OPERAND);
	}
	if (!ret_buffer_desc) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	if (ACPI_GET_OBJECT_TYPE(obj_desc) == 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);
			}
		}
	} else
	    if ((ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REGION_FIELD)
		&& (obj_desc->field.region_obj->region.space_id ==
		    ACPI_ADR_SPACE_SMBUS)) {
		/*
		 * This is an SMBus read.  We must create a buffer to hold the data
		 * and directly access the region handler.
		 */
		buffer_desc =
		    acpi_ut_create_buffer_object(ACPI_SMBUS_BUFFER_SIZE);
		if (!buffer_desc) {
			return_ACPI_STATUS(AE_NO_MEMORY);
		}

		/* Lock entire transaction if requested */

		acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);

		/*
		 * Perform the read.
		 * Note: Smbus protocol value is passed in upper 16-bits of Function
		 */
		status = acpi_ex_access_region(obj_desc, 0,
					       ACPI_CAST_PTR(acpi_integer,
							     buffer_desc->
							     buffer.pointer),
					       ACPI_READ | (obj_desc->field.
							    attribute << 16));
		acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
		goto exit;
	}

	/*
	 * Allocate a buffer for the contents of the field.
	 *
	 * If the field is larger than the size of an acpi_integer, create
	 * a BUFFER to hold it.  Otherwise, use an INTEGER.  This allows
	 * the use of arithmetic operators on the returned value if the
	 * field size is equal or smaller than an Integer.
	 *
	 * Note: Field.length is in bits.
	 */
	length =
	    (acpi_size) ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length);
	if (length > acpi_gbl_integer_byte_width) {

		/* Field is too large for an Integer, create a Buffer instead */

		buffer_desc = acpi_ut_create_buffer_object(length);
		if (!buffer_desc) {
			return_ACPI_STATUS(AE_NO_MEMORY);
		}
		buffer = buffer_desc->buffer.pointer;
	} else {
		/* Field will fit within an Integer (normal case) */

		buffer_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
		if (!buffer_desc) {
			return_ACPI_STATUS(AE_NO_MEMORY);
		}

		length = acpi_gbl_integer_byte_width;
		buffer_desc->integer.value = 0;
		buffer = &buffer_desc->integer.value;
	}

	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
			  "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
			  obj_desc, ACPI_GET_OBJECT_TYPE(obj_desc), buffer,
			  (u32) length));
	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
			  "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
			  obj_desc->common_field.bit_length,
			  obj_desc->common_field.start_field_bit_offset,
			  obj_desc->common_field.base_byte_offset));

	/* Lock entire transaction if requested */

	acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);

	/* Read from the field */

	status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length);
	acpi_ex_release_global_lock(obj_desc->common_field.field_flags);

      exit:
	if (ACPI_FAILURE(status)) {
		acpi_ut_remove_reference(buffer_desc);
	} else {
		*ret_buffer_desc = buffer_desc;
	}

	return_ACPI_STATUS(status);
}
Пример #12
0
acpi_status
acpi_ex_insert_into_field (
	union acpi_operand_object       *obj_desc,
	void                            *buffer,
	u32                             buffer_length)
{
	acpi_status                     status;
	acpi_integer                    mask;
	acpi_integer                    merged_datum;
	acpi_integer                    raw_datum = 0;
	u32                             field_offset = 0;
	u32                             buffer_offset = 0;
	u32                             buffer_tail_bits;
	u32                             datum_count;
	u32                             field_datum_count;
	u32                             i;


	ACPI_FUNCTION_TRACE ("ex_insert_into_field");


	/* Validate input buffer */

	if (buffer_length < ACPI_ROUND_BITS_UP_TO_BYTES (
			 obj_desc->common_field.bit_length)) {
		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
			"Field size %X (bits) is too large for buffer (%X)\n",
			obj_desc->common_field.bit_length, buffer_length));

		return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
	}

	/* Compute the number of datums (access width data items) */

	mask = ACPI_MASK_BITS_BELOW (obj_desc->common_field.start_field_bit_offset);
	datum_count = ACPI_ROUND_UP_TO (obj_desc->common_field.bit_length,
			  obj_desc->common_field.access_bit_width);
	field_datum_count = ACPI_ROUND_UP_TO (obj_desc->common_field.bit_length +
			   obj_desc->common_field.start_field_bit_offset,
			   obj_desc->common_field.access_bit_width);

	/* Get initial Datum from the input buffer */

	ACPI_MEMCPY (&raw_datum, buffer,
		ACPI_MIN(obj_desc->common_field.access_byte_width,
				 buffer_length - buffer_offset));

	merged_datum = raw_datum << obj_desc->common_field.start_field_bit_offset;

	/* Write the entire field */

	for (i = 1; i < field_datum_count; i++) {
		/* Write merged datum to the target field */

		merged_datum &= mask;
		status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_offset);
		if (ACPI_FAILURE (status)) {
			return_ACPI_STATUS (status);
		}

		/* Start new output datum by merging with previous input datum */

		field_offset += obj_desc->common_field.access_byte_width;
		merged_datum = raw_datum >>
			(obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset);
		mask = ACPI_INTEGER_MAX;

		if (i == datum_count) {
			break;
		}

		/* Get the next input datum from the buffer */

		buffer_offset += obj_desc->common_field.access_byte_width;
		ACPI_MEMCPY (&raw_datum, ((char *) buffer) + buffer_offset,
			ACPI_MIN(obj_desc->common_field.access_byte_width,
					 buffer_length - buffer_offset));
		merged_datum |= raw_datum << obj_desc->common_field.start_field_bit_offset;
	}

	/* Mask off any extra bits in the last datum */

	buffer_tail_bits = (obj_desc->common_field.bit_length +
			obj_desc->common_field.start_field_bit_offset) % obj_desc->common_field.access_bit_width;
	if (buffer_tail_bits) {
		mask &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits);
	}

	/* Write the last datum to the field */

	merged_datum &= mask;
	status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_offset);

	return_ACPI_STATUS (status);
}
Пример #13
0
acpi_status
acpi_ex_extract_from_field (
	union acpi_operand_object       *obj_desc,
	void                            *buffer,
	u32                             buffer_length)
{
	acpi_status                     status;
	acpi_integer                    raw_datum;
	acpi_integer                    merged_datum;
	u32                             field_offset = 0;
	u32                             buffer_offset = 0;
	u32                             buffer_tail_bits;
	u32                             datum_count;
	u32                             field_datum_count;
	u32                             i;


	ACPI_FUNCTION_TRACE ("ex_extract_from_field");


	/* Validate target buffer and clear it */

	if (buffer_length < ACPI_ROUND_BITS_UP_TO_BYTES (
			 obj_desc->common_field.bit_length)) {
		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
			"Field size %X (bits) is too large for buffer (%X)\n",
			obj_desc->common_field.bit_length, buffer_length));

		return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
	}
	ACPI_MEMSET (buffer, 0, buffer_length);

	/* Compute the number of datums (access width data items) */

	datum_count = ACPI_ROUND_UP_TO (
			   obj_desc->common_field.bit_length,
			   obj_desc->common_field.access_bit_width);
	field_datum_count = ACPI_ROUND_UP_TO (
			   obj_desc->common_field.bit_length +
			   obj_desc->common_field.start_field_bit_offset,
			   obj_desc->common_field.access_bit_width);

	/* Priming read from the field */

	status = acpi_ex_field_datum_io (obj_desc, field_offset, &raw_datum, ACPI_READ);
	if (ACPI_FAILURE (status)) {
		return_ACPI_STATUS (status);
	}
	merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset;

	/* Read the rest of the field */

	for (i = 1; i < field_datum_count; i++) {
		/* Get next input datum from the field */

		field_offset += obj_desc->common_field.access_byte_width;
		status = acpi_ex_field_datum_io (obj_desc, field_offset,
				  &raw_datum, ACPI_READ);
		if (ACPI_FAILURE (status)) {
			return_ACPI_STATUS (status);
		}

		/* Merge with previous datum if necessary */

		merged_datum |= raw_datum <<
			(obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset);

		if (i == datum_count) {
			break;
		}

		/* Write merged datum to target buffer */

		ACPI_MEMCPY (((char *) buffer) + buffer_offset, &merged_datum,
			ACPI_MIN(obj_desc->common_field.access_byte_width,
					 buffer_length - buffer_offset));

		buffer_offset += obj_desc->common_field.access_byte_width;
		merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset;
	}

	/* Mask off any extra bits in the last datum */

	buffer_tail_bits = obj_desc->common_field.bit_length % obj_desc->common_field.access_bit_width;
	if (buffer_tail_bits) {
		merged_datum &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits);
	}

	/* Write the last datum to the buffer */

	ACPI_MEMCPY (((char *) buffer) + buffer_offset, &merged_datum,
		ACPI_MIN(obj_desc->common_field.access_byte_width,
				 buffer_length - buffer_offset));

	return_ACPI_STATUS (AE_OK);
}
Пример #14
0
acpi_status
acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
			  void *buffer, u32 buffer_length)
{
	acpi_status status;
	acpi_integer mask;
	acpi_integer width_mask;
	acpi_integer merged_datum;
	acpi_integer raw_datum = 0;
	u32 field_offset = 0;
	u32 buffer_offset = 0;
	u32 buffer_tail_bits;
	u32 datum_count;
	u32 field_datum_count;
	u32 i;

	ACPI_FUNCTION_TRACE(ex_insert_into_field);

	/* Validate input buffer */

	if (buffer_length <
	    ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) {
		ACPI_ERROR((AE_INFO,
			    "Field size %X (bits) is too large for buffer (%X)",
			    obj_desc->common_field.bit_length, buffer_length));

		return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
	}

	/*
	 * Create the bitmasks used for bit insertion.
	 * Note: This if/else is used to bypass compiler differences with the
	 * shift operator
	 */
	if (obj_desc->common_field.access_bit_width == ACPI_INTEGER_BIT_SIZE) {
		width_mask = ACPI_INTEGER_MAX;
	} else {
		width_mask =
		    ACPI_MASK_BITS_ABOVE(obj_desc->common_field.
					 access_bit_width);
	}

	mask = width_mask &
	    ACPI_MASK_BITS_BELOW(obj_desc->common_field.start_field_bit_offset);

	/* Compute the number of datums (access width data items) */

	datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
				       obj_desc->common_field.access_bit_width);

	field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
					     obj_desc->common_field.
					     start_field_bit_offset,
					     obj_desc->common_field.
					     access_bit_width);

	/* Get initial Datum from the input buffer */

	ACPI_MEMCPY(&raw_datum, buffer,
		    ACPI_MIN(obj_desc->common_field.access_byte_width,
			     buffer_length - buffer_offset));

	merged_datum =
	    raw_datum << obj_desc->common_field.start_field_bit_offset;

	/* Write the entire field */

	for (i = 1; i < field_datum_count; i++) {

		/* Write merged datum to the target field */

		merged_datum &= mask;
		status = acpi_ex_write_with_update_rule(obj_desc, mask,
							merged_datum,
							field_offset);
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
		}

		field_offset += obj_desc->common_field.access_byte_width;

		/*
		 * Start new output datum by merging with previous input datum
		 * if necessary.
		 *
		 * Note: Before the shift, check if the shift value will be larger than
		 * the integer size. If so, there is no need to perform the operation.
		 * This avoids the differences in behavior between different compilers
		 * concerning shift values larger than the target data width.
		 */
		if ((obj_desc->common_field.access_bit_width -
		     obj_desc->common_field.start_field_bit_offset) <
		    ACPI_INTEGER_BIT_SIZE) {
			merged_datum =
			    raw_datum >> (obj_desc->common_field.
					  access_bit_width -
					  obj_desc->common_field.
					  start_field_bit_offset);
		} else {
Пример #15
0
static ACPI_STATUS
AcpiDbTestBufferType (
    ACPI_NAMESPACE_NODE     *Node,
    UINT32                  BitLength)
{
    ACPI_OBJECT             *Temp1 = NULL;
    ACPI_OBJECT             *Temp2 = NULL;
    ACPI_OBJECT             *Temp3 = NULL;
    UINT8                   *Buffer;
    ACPI_OBJECT             WriteValue;
    ACPI_STATUS             Status;
    UINT32                  ByteLength;
    UINT32                  i;
    UINT8                   ExtraBits;


    ByteLength = ACPI_ROUND_BITS_UP_TO_BYTES (BitLength);
    if (ByteLength == 0)
    {
        AcpiOsPrintf (" Ignoring zero length buffer");
        return (AE_OK);
    }

    /* Allocate a local buffer */

    Buffer = ACPI_ALLOCATE_ZEROED (ByteLength);
    if (!Buffer)
    {
        return (AE_NO_MEMORY);
    }

    /* Read the original value */

    Status = AcpiDbReadFromObject (Node, ACPI_TYPE_BUFFER, &Temp1);
    if (ACPI_FAILURE (Status))
    {
        goto Exit;
    }

    /* Emit a few bytes of the buffer */

    AcpiOsPrintf (" (%4.4X/%3.3X)", BitLength, Temp1->Buffer.Length);
    for (i = 0; ((i < 4) && (i < ByteLength)); i++)
    {
        AcpiOsPrintf (" %2.2X", Temp1->Buffer.Pointer[i]);
    }
    AcpiOsPrintf ("...  ");

    /*
     * Write a new value.
     *
     * Handle possible extra bits at the end of the buffer. Can
     * happen for FieldUnits larger than an integer, but the bit
     * count is not an integral number of bytes. Zero out the
     * unused bits.
     */
    memset (Buffer, BUFFER_FILL_VALUE, ByteLength);
    ExtraBits = BitLength % 8;
    if (ExtraBits)
    {
        Buffer [ByteLength - 1] = ACPI_MASK_BITS_ABOVE (ExtraBits);
    }

    WriteValue.Type = ACPI_TYPE_BUFFER;
    WriteValue.Buffer.Length = ByteLength;
    WriteValue.Buffer.Pointer = Buffer;

    Status = AcpiDbWriteToObject (Node, &WriteValue);
    if (ACPI_FAILURE (Status))
    {
        goto Exit;
    }

    /* Ensure that we can read back the new value */

    Status = AcpiDbReadFromObject (Node, ACPI_TYPE_BUFFER, &Temp2);
    if (ACPI_FAILURE (Status))
    {
        goto Exit;
    }

    if (memcmp (Temp2->Buffer.Pointer, Buffer, ByteLength))
    {
        AcpiOsPrintf (" MISMATCH 2: New buffer value");
    }

    /* Write back the original value */

    WriteValue.Buffer.Length = ByteLength;
    WriteValue.Buffer.Pointer = Temp1->Buffer.Pointer;

    Status = AcpiDbWriteToObject (Node, &WriteValue);
    if (ACPI_FAILURE (Status))
    {
        goto Exit;
    }

    /* Ensure that we can read back the original value */

    Status = AcpiDbReadFromObject (Node, ACPI_TYPE_BUFFER, &Temp3);
    if (ACPI_FAILURE (Status))
    {
        goto Exit;
    }

    if (memcmp (Temp1->Buffer.Pointer,
            Temp3->Buffer.Pointer, ByteLength))
    {
        AcpiOsPrintf (" MISMATCH 3: While restoring original buffer");
    }

Exit:
    ACPI_FREE (Buffer);
    if (Temp1) {AcpiOsFree (Temp1);}
    if (Temp2) {AcpiOsFree (Temp2);}
    if (Temp3) {AcpiOsFree (Temp3);}
    return (Status);
}
Пример #16
0
ACPI_STATUS
AcpiExPrepFieldValue (
    ACPI_CREATE_FIELD_INFO  *Info)
{
    ACPI_OPERAND_OBJECT     *ObjDesc;
    ACPI_OPERAND_OBJECT     *SecondDesc = NULL;
    ACPI_STATUS             Status;
    UINT32                  AccessByteWidth;
    UINT32                  Type;


    ACPI_FUNCTION_TRACE (ExPrepFieldValue);


    /* Parameter validation */

    if (Info->FieldType != ACPI_TYPE_LOCAL_INDEX_FIELD)
    {
        if (!Info->RegionNode)
        {
            ACPI_ERROR ((AE_INFO, "Null RegionNode"));
            return_ACPI_STATUS (AE_AML_NO_OPERAND);
        }

        Type = AcpiNsGetType (Info->RegionNode);
        if (Type != ACPI_TYPE_REGION)
        {
            ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)",
                Type, AcpiUtGetTypeName (Type)));

            return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
        }
    }

    /* Allocate a new field object */

    ObjDesc = AcpiUtCreateInternalObject (Info->FieldType);
    if (!ObjDesc)
    {
        return_ACPI_STATUS (AE_NO_MEMORY);
    }

    /* Initialize areas of the object that are common to all fields */

    ObjDesc->CommonField.Node = Info->FieldNode;
    Status = AcpiExPrepCommonFieldObject (ObjDesc,
                Info->FieldFlags, Info->Attribute,
                Info->FieldBitPosition, Info->FieldBitLength);
    if (ACPI_FAILURE (Status))
    {
        AcpiUtDeleteObjectDesc (ObjDesc);
        return_ACPI_STATUS (Status);
    }

    /* Initialize areas of the object that are specific to the field type */

    switch (Info->FieldType)
    {
    case ACPI_TYPE_LOCAL_REGION_FIELD:

        ObjDesc->Field.RegionObj = AcpiNsGetAttachedObject (Info->RegionNode);

        /* Fields specific to GenericSerialBus fields */

        ObjDesc->Field.AccessLength = Info->AccessLength;

        if (Info->ConnectionNode)
        {
            SecondDesc = Info->ConnectionNode->Object;
            if (!(SecondDesc->Common.Flags & AOPOBJ_DATA_VALID))
            {
                Status = AcpiDsGetBufferArguments (SecondDesc);
                if (ACPI_FAILURE (Status))
                {
                    AcpiUtDeleteObjectDesc (ObjDesc);
                    return_ACPI_STATUS (Status);
                }
            }

            ObjDesc->Field.ResourceBuffer = SecondDesc->Buffer.Pointer;
            ObjDesc->Field.ResourceLength = (UINT16) SecondDesc->Buffer.Length;
        }
        else if (Info->ResourceBuffer)
        {
            ObjDesc->Field.ResourceBuffer = Info->ResourceBuffer;
            ObjDesc->Field.ResourceLength = Info->ResourceLength;
        }

        /* Allow full data read from EC address space */

        if ((ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_EC) &&
            (ObjDesc->CommonField.BitLength > 8))
        {
            AccessByteWidth = ACPI_ROUND_BITS_UP_TO_BYTES (
                ObjDesc->CommonField.BitLength);

            /* Maximum byte width supported is 255 */

            if (AccessByteWidth < 256)
            {
                ObjDesc->CommonField.AccessByteWidth = (UINT8) AccessByteWidth;
            }
        }

        /* An additional reference for the container */

        AcpiUtAddReference (ObjDesc->Field.RegionObj);

        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
            "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n",
            ObjDesc->Field.StartFieldBitOffset, ObjDesc->Field.BaseByteOffset,
            ObjDesc->Field.AccessByteWidth, ObjDesc->Field.RegionObj));
        break;

    case ACPI_TYPE_LOCAL_BANK_FIELD:

        ObjDesc->BankField.Value = Info->BankValue;
        ObjDesc->BankField.RegionObj =
            AcpiNsGetAttachedObject (Info->RegionNode);
        ObjDesc->BankField.BankObj =
            AcpiNsGetAttachedObject (Info->RegisterNode);

        /* An additional reference for the attached objects */

        AcpiUtAddReference (ObjDesc->BankField.RegionObj);
        AcpiUtAddReference (ObjDesc->BankField.BankObj);

        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
            "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n",
            ObjDesc->BankField.StartFieldBitOffset,
            ObjDesc->BankField.BaseByteOffset,
            ObjDesc->Field.AccessByteWidth,
            ObjDesc->BankField.RegionObj,
            ObjDesc->BankField.BankObj));

        /*
         * Remember location in AML stream of the field unit
         * opcode and operands -- since the BankValue
         * operands must be evaluated.
         */
        SecondDesc = ObjDesc->Common.NextObject;
        SecondDesc->Extra.AmlStart = ACPI_CAST_PTR (ACPI_PARSE_OBJECT,
            Info->DataRegisterNode)->Named.Data;
        SecondDesc->Extra.AmlLength = ACPI_CAST_PTR (ACPI_PARSE_OBJECT,
            Info->DataRegisterNode)->Named.Length;

        break;

    case ACPI_TYPE_LOCAL_INDEX_FIELD:

        /* Get the Index and Data registers */

        ObjDesc->IndexField.IndexObj =
            AcpiNsGetAttachedObject (Info->RegisterNode);
        ObjDesc->IndexField.DataObj =
            AcpiNsGetAttachedObject (Info->DataRegisterNode);

        if (!ObjDesc->IndexField.DataObj || !ObjDesc->IndexField.IndexObj)
        {
            ACPI_ERROR ((AE_INFO, "Null Index Object during field prep"));
            AcpiUtDeleteObjectDesc (ObjDesc);
            return_ACPI_STATUS (AE_AML_INTERNAL);
        }

        /* An additional reference for the attached objects */

        AcpiUtAddReference (ObjDesc->IndexField.DataObj);
        AcpiUtAddReference (ObjDesc->IndexField.IndexObj);

        /*
         * April 2006: Changed to match MS behavior
         *
         * The value written to the Index register is the byte offset of the
         * target field in units of the granularity of the IndexField
         *
         * Previously, the value was calculated as an index in terms of the
         * width of the Data register, as below:
         *
         *      ObjDesc->IndexField.Value = (UINT32)
         *          (Info->FieldBitPosition / ACPI_MUL_8 (
         *              ObjDesc->Field.AccessByteWidth));
         *
         * February 2006: Tried value as a byte offset:
         *      ObjDesc->IndexField.Value = (UINT32)
         *          ACPI_DIV_8 (Info->FieldBitPosition);
         */
        ObjDesc->IndexField.Value = (UINT32) ACPI_ROUND_DOWN (
            ACPI_DIV_8 (Info->FieldBitPosition),
            ObjDesc->IndexField.AccessByteWidth);

        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
            "IndexField: BitOff %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n",
            ObjDesc->IndexField.StartFieldBitOffset,
            ObjDesc->IndexField.BaseByteOffset,
            ObjDesc->IndexField.Value,
            ObjDesc->Field.AccessByteWidth,
            ObjDesc->IndexField.IndexObj,
            ObjDesc->IndexField.DataObj));
        break;

    default:

        /* No other types should get here */

        break;
    }

    /*
     * Store the constructed descriptor (ObjDesc) into the parent Node,
     * preserving the current type of that NamedObj.
     */
    Status = AcpiNsAttachObject (Info->FieldNode, ObjDesc,
                AcpiNsGetType (Info->FieldNode));

    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Set NamedObj %p [%4.4s], ObjDesc %p\n",
        Info->FieldNode, AcpiUtGetNodeName (Info->FieldNode), ObjDesc));

    /* Remove local reference to the object */

    AcpiUtRemoveReference (ObjDesc);
    return_ACPI_STATUS (Status);
}
Пример #17
0
static acpi_status
acpi_db_test_one_object(acpi_handle obj_handle,
			u32 nesting_level, void *context, void **return_value)
{
	struct acpi_namespace_node *node;
	union acpi_operand_object *obj_desc;
	union acpi_operand_object *region_obj;
	acpi_object_type local_type;
	u32 bit_length = 0;
	u32 byte_length = 0;
	acpi_status status = AE_OK;

	node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);
	obj_desc = node->object;

	/*
	 * For the supported types, get the actual bit length or
	 * byte length. Map the type to one of Integer/String/Buffer.
	 */
	switch (node->type) {
	case ACPI_TYPE_INTEGER:

		/* Integer width is either 32 or 64 */

		local_type = ACPI_TYPE_INTEGER;
		bit_length = acpi_gbl_integer_bit_width;
		break;

	case ACPI_TYPE_STRING:

		local_type = ACPI_TYPE_STRING;
		byte_length = obj_desc->string.length;
		break;

	case ACPI_TYPE_BUFFER:

		local_type = ACPI_TYPE_BUFFER;
		byte_length = obj_desc->buffer.length;
		bit_length = byte_length * 8;
		break;

	case ACPI_TYPE_FIELD_UNIT:
	case ACPI_TYPE_BUFFER_FIELD:
	case ACPI_TYPE_LOCAL_REGION_FIELD:
	case ACPI_TYPE_LOCAL_INDEX_FIELD:
	case ACPI_TYPE_LOCAL_BANK_FIELD:

		local_type = ACPI_TYPE_INTEGER;
		if (obj_desc) {
			/*
			 * Returned object will be a Buffer if the field length
			 * is larger than the size of an Integer (32 or 64 bits
			 * depending on the DSDT version).
			 */
			bit_length = obj_desc->common_field.bit_length;
			byte_length = ACPI_ROUND_BITS_UP_TO_BYTES(bit_length);
			if (bit_length > acpi_gbl_integer_bit_width) {
				local_type = ACPI_TYPE_BUFFER;
			}
		}
		break;

	default:

		/* Ignore all other types */

		return (AE_OK);
	}

	/* Emit the common prefix: Type:Name */

	acpi_os_printf("%14s: %4.4s",
		       acpi_ut_get_type_name(node->type), node->name.ascii);
	if (!obj_desc) {
		acpi_os_printf(" Ignoring, no attached object\n");
		return (AE_OK);
	}

	/*
	 * Check for unsupported region types. Note: acpi_exec simulates
	 * access to system_memory, system_IO, PCI_Config, and EC.
	 */
	switch (node->type) {
	case ACPI_TYPE_LOCAL_REGION_FIELD:

		region_obj = obj_desc->field.region_obj;
		switch (region_obj->region.space_id) {
		case ACPI_ADR_SPACE_SYSTEM_MEMORY:
		case ACPI_ADR_SPACE_SYSTEM_IO:
		case ACPI_ADR_SPACE_PCI_CONFIG:
		case ACPI_ADR_SPACE_EC:

			break;

		default:

			acpi_os_printf
			    ("    %s space is not supported [%4.4s]\n",
			     acpi_ut_get_region_name(region_obj->region.
						     space_id),
			     region_obj->region.node->name.ascii);
			return (AE_OK);
		}
		break;

	default:
		break;
	}

	/* At this point, we have resolved the object to one of the major types */

	switch (local_type) {
	case ACPI_TYPE_INTEGER:

		status = acpi_db_test_integer_type(node, bit_length);
		break;

	case ACPI_TYPE_STRING:

		status = acpi_db_test_string_type(node, byte_length);
		break;

	case ACPI_TYPE_BUFFER:

		status = acpi_db_test_buffer_type(node, bit_length);
		break;

	default:

		acpi_os_printf(" Ignoring, type not implemented (%2.2X)",
			       local_type);
		break;
	}

	switch (node->type) {
	case ACPI_TYPE_LOCAL_REGION_FIELD:

		region_obj = obj_desc->field.region_obj;
		acpi_os_printf(" (%s)",
			       acpi_ut_get_region_name(region_obj->region.
						       space_id));
		break;

	default:
		break;
	}

	acpi_os_printf("\n");
	return (status);
}
Пример #18
0
acpi_status
acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
			  void *buffer, u32 buffer_length)
{
	void *new_buffer;
	acpi_status status;
	u64 mask;
	u64 width_mask;
	u64 merged_datum;
	u64 raw_datum = 0;
	u32 field_offset = 0;
	u32 buffer_offset = 0;
	u32 buffer_tail_bits;
	u32 datum_count;
	u32 field_datum_count;
	u32 access_bit_width;
	u32 required_length;
	u32 i;

	ACPI_FUNCTION_TRACE(ex_insert_into_field);

	/* Validate input buffer */

	new_buffer = NULL;
	required_length =
	    ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length);
	/*
	 * We must have a buffer that is at least as long as the field
	 * we are writing to. This is because individual fields are
	 * indivisible and partial writes are not supported -- as per
	 * the ACPI specification.
	 */
	if (buffer_length < required_length) {

		/* We need to create a new buffer */

		new_buffer = ACPI_ALLOCATE_ZEROED(required_length);
		if (!new_buffer) {
			return_ACPI_STATUS(AE_NO_MEMORY);
		}

		/*
		 * Copy the original data to the new buffer, starting
		 * at Byte zero. All unused (upper) bytes of the
		 * buffer will be 0.
		 */
		ACPI_MEMCPY((char *)new_buffer, (char *)buffer, buffer_length);
		buffer = new_buffer;
		buffer_length = required_length;
	}

/* TBD: Move to common setup code */

	/* Algo is limited to sizeof(u64), so cut the access_byte_width */
	if (obj_desc->common_field.access_byte_width > sizeof(u64)) {
		obj_desc->common_field.access_byte_width = sizeof(u64);
	}

	access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width);

	/*
	 * Create the bitmasks used for bit insertion.
	 * Note: This if/else is used to bypass compiler differences with the
	 * shift operator
	 */
	if (access_bit_width == ACPI_INTEGER_BIT_SIZE) {
		width_mask = ACPI_UINT64_MAX;
	} else {
		width_mask = ACPI_MASK_BITS_ABOVE(access_bit_width);
	}

	mask = width_mask &
	    ACPI_MASK_BITS_BELOW(obj_desc->common_field.start_field_bit_offset);

	/* Compute the number of datums (access width data items) */

	datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
				       access_bit_width);

	field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length +
					     obj_desc->common_field.
					     start_field_bit_offset,
					     access_bit_width);

	/* Get initial Datum from the input buffer */

	ACPI_MEMCPY(&raw_datum, buffer,
		    ACPI_MIN(obj_desc->common_field.access_byte_width,
			     buffer_length - buffer_offset));

	merged_datum =
	    raw_datum << obj_desc->common_field.start_field_bit_offset;

	/* Write the entire field */

	for (i = 1; i < field_datum_count; i++) {

		/* Write merged datum to the target field */

		merged_datum &= mask;
		status = acpi_ex_write_with_update_rule(obj_desc, mask,
							merged_datum,
							field_offset);
		if (ACPI_FAILURE(status)) {
			goto exit;
		}

		field_offset += obj_desc->common_field.access_byte_width;

		/*
		 * Start new output datum by merging with previous input datum
		 * if necessary.
		 *
		 * Note: Before the shift, check if the shift value will be larger than
		 * the integer size. If so, there is no need to perform the operation.
		 * This avoids the differences in behavior between different compilers
		 * concerning shift values larger than the target data width.
		 */
		if ((access_bit_width -
		     obj_desc->common_field.start_field_bit_offset) <
		    ACPI_INTEGER_BIT_SIZE) {
			merged_datum =
			    raw_datum >> (access_bit_width -
					  obj_desc->common_field.
					  start_field_bit_offset);
		} else {
Пример #19
0
static acpi_status
acpi_db_test_integer_type(struct acpi_namespace_node *node, u32 bit_length)
{
	union acpi_object *temp1 = NULL;
	union acpi_object *temp2 = NULL;
	union acpi_object *temp3 = NULL;
	union acpi_object write_value;
	u64 value_to_write;
	acpi_status status;

	if (bit_length > 64) {
		acpi_os_printf(" Invalid length for an Integer: %u",
			       bit_length);
		return (AE_OK);
	}

	/* Read the original value */

	status = acpi_db_read_from_object(node, ACPI_TYPE_INTEGER, &temp1);
	if (ACPI_FAILURE(status)) {
		return (status);
	}

	acpi_os_printf(" (%4.4X/%3.3X) %8.8X%8.8X",
		       bit_length, ACPI_ROUND_BITS_UP_TO_BYTES(bit_length),
		       ACPI_FORMAT_UINT64(temp1->integer.value));

	value_to_write = ACPI_UINT64_MAX >> (64 - bit_length);
	if (temp1->integer.value == value_to_write) {
		value_to_write = 0;
	}

	/* Write a new value */

	write_value.type = ACPI_TYPE_INTEGER;
	write_value.integer.value = value_to_write;
	status = acpi_db_write_to_object(node, &write_value);
	if (ACPI_FAILURE(status)) {
		goto exit;
	}

	/* Ensure that we can read back the new value */

	status = acpi_db_read_from_object(node, ACPI_TYPE_INTEGER, &temp2);
	if (ACPI_FAILURE(status)) {
		goto exit;
	}

	if (temp2->integer.value != value_to_write) {
		acpi_os_printf(" MISMATCH 2: %8.8X%8.8X, expecting %8.8X%8.8X",
			       ACPI_FORMAT_UINT64(temp2->integer.value),
			       ACPI_FORMAT_UINT64(value_to_write));
	}

	/* Write back the original value */

	write_value.integer.value = temp1->integer.value;
	status = acpi_db_write_to_object(node, &write_value);
	if (ACPI_FAILURE(status)) {
		goto exit;
	}

	/* Ensure that we can read back the original value */

	status = acpi_db_read_from_object(node, ACPI_TYPE_INTEGER, &temp3);
	if (ACPI_FAILURE(status)) {
		goto exit;
	}

	if (temp3->integer.value != temp1->integer.value) {
		acpi_os_printf(" MISMATCH 3: %8.8X%8.8X, expecting %8.8X%8.8X",
			       ACPI_FORMAT_UINT64(temp3->integer.value),
			       ACPI_FORMAT_UINT64(temp1->integer.value));
	}

exit:
	if (temp1) {
		acpi_os_free(temp1);
	}
	if (temp2) {
		acpi_os_free(temp2);
	}
	if (temp3) {
		acpi_os_free(temp3);
	}
	return (AE_OK);
}
Пример #20
0
ACPI_STATUS
AcpiExExtractFromField (
    ACPI_OPERAND_OBJECT     *ObjDesc,
    void                    *Buffer,
    UINT32                  BufferLength)
{
    ACPI_STATUS             Status;
    UINT64                  RawDatum;
    UINT64                  MergedDatum;
    UINT32                  FieldOffset = 0;
    UINT32                  BufferOffset = 0;
    UINT32                  BufferTailBits;
    UINT32                  DatumCount;
    UINT32                  FieldDatumCount;
    UINT32                  AccessBitWidth;
    UINT32                  i;


    ACPI_FUNCTION_TRACE (ExExtractFromField);


    /* Validate target buffer and clear it */

    if (BufferLength <
        ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength))
    {
        ACPI_ERROR ((AE_INFO,
            "Field size %u (bits) is too large for buffer (%u)",
            ObjDesc->CommonField.BitLength, BufferLength));

        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
    }

    memset (Buffer, 0, BufferLength);
    AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);

    /* Handle the simple case here */

    if ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&
        (ObjDesc->CommonField.BitLength == AccessBitWidth))
    {
        if (BufferLength >= sizeof (UINT64))
        {
            Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ);
        }
        else
        {
            /* Use RawDatum (UINT64) to handle buffers < 64 bits */

            Status = AcpiExFieldDatumIo (ObjDesc, 0, &RawDatum, ACPI_READ);
            memcpy (Buffer, &RawDatum, BufferLength);
        }

        return_ACPI_STATUS (Status);
    }

/* TBD: Move to common setup code */

    /* Field algorithm is limited to sizeof(UINT64), truncate if needed */

    if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
    {
        ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
        AccessBitWidth = sizeof (UINT64) * 8;
    }

    /* Compute the number of datums (access width data items) */

    DatumCount = ACPI_ROUND_UP_TO (
        ObjDesc->CommonField.BitLength, AccessBitWidth);

    FieldDatumCount = ACPI_ROUND_UP_TO (
        ObjDesc->CommonField.BitLength +
        ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth);

    /* Priming read from the field */

    Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ);
    if (ACPI_FAILURE (Status))
    {
        return_ACPI_STATUS (Status);
    }
    MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;

    /* Read the rest of the field */

    for (i = 1; i < FieldDatumCount; i++)
    {
        /* Get next input datum from the field */

        FieldOffset += ObjDesc->CommonField.AccessByteWidth;
        Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset,
                    &RawDatum, ACPI_READ);
        if (ACPI_FAILURE (Status))
        {
            return_ACPI_STATUS (Status);
        }

        /*
         * Merge with previous datum if necessary.
         *
         * Note: Before the shift, check if the shift value will be larger than
         * the integer size. If so, there is no need to perform the operation.
         * This avoids the differences in behavior between different compilers
         * concerning shift values larger than the target data width.
         */
        if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset <
            ACPI_INTEGER_BIT_SIZE)
        {
            MergedDatum |= RawDatum <<
                (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
        }

        if (i == DatumCount)
        {
            break;
        }

        /* Write merged datum to target buffer */

        memcpy (((char *) Buffer) + BufferOffset, &MergedDatum,
            ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
                BufferLength - BufferOffset));

        BufferOffset += ObjDesc->CommonField.AccessByteWidth;
        MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
    }

    /* Mask off any extra bits in the last datum */

    BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth;
    if (BufferTailBits)
    {
        MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
    }

    /* Write the last datum to the buffer */

    memcpy (((char *) Buffer) + BufferOffset, &MergedDatum,
        ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
            BufferLength - BufferOffset));

    return_ACPI_STATUS (AE_OK);
}
Пример #21
0
static acpi_status
acpi_db_test_buffer_type(struct acpi_namespace_node *node, u32 bit_length)
{
	union acpi_object *temp1 = NULL;
	union acpi_object *temp2 = NULL;
	union acpi_object *temp3 = NULL;
	u8 *buffer;
	union acpi_object write_value;
	acpi_status status;
	u32 byte_length;
	u32 i;
	u8 extra_bits;

	byte_length = ACPI_ROUND_BITS_UP_TO_BYTES(bit_length);
	if (byte_length == 0) {
		acpi_os_printf(" Ignoring zero length buffer");
		return (AE_OK);
	}

	/* Allocate a local buffer */

	buffer = ACPI_ALLOCATE_ZEROED(byte_length);
	if (!buffer) {
		return (AE_NO_MEMORY);
	}

	/* Read the original value */

	status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp1);
	if (ACPI_FAILURE(status)) {
		goto exit;
	}

	/* Emit a few bytes of the buffer */

	acpi_os_printf(" (%4.4X/%3.3X)", bit_length, temp1->buffer.length);
	for (i = 0; ((i < 4) && (i < byte_length)); i++) {
		acpi_os_printf(" %2.2X", temp1->buffer.pointer[i]);
	}
	acpi_os_printf("... ");

	/*
	 * Write a new value.
	 *
	 * Handle possible extra bits at the end of the buffer. Can
	 * happen for field_units larger than an integer, but the bit
	 * count is not an integral number of bytes. Zero out the
	 * unused bits.
	 */
	memset(buffer, BUFFER_FILL_VALUE, byte_length);
	extra_bits = bit_length % 8;
	if (extra_bits) {
		buffer[byte_length - 1] = ACPI_MASK_BITS_ABOVE(extra_bits);
	}

	write_value.type = ACPI_TYPE_BUFFER;
	write_value.buffer.length = byte_length;
	write_value.buffer.pointer = buffer;

	status = acpi_db_write_to_object(node, &write_value);
	if (ACPI_FAILURE(status)) {
		goto exit;
	}

	/* Ensure that we can read back the new value */

	status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp2);
	if (ACPI_FAILURE(status)) {
		goto exit;
	}

	if (memcmp(temp2->buffer.pointer, buffer, byte_length)) {
		acpi_os_printf(" MISMATCH 2: New buffer value");
	}

	/* Write back the original value */

	write_value.buffer.length = byte_length;
	write_value.buffer.pointer = temp1->buffer.pointer;

	status = acpi_db_write_to_object(node, &write_value);
	if (ACPI_FAILURE(status)) {
		goto exit;
	}

	/* Ensure that we can read back the original value */

	status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp3);
	if (ACPI_FAILURE(status)) {
		goto exit;
	}

	if (memcmp(temp1->buffer.pointer, temp3->buffer.pointer, byte_length)) {
		acpi_os_printf(" MISMATCH 3: While restoring original buffer");
	}

exit:
	ACPI_FREE(buffer);
	if (temp1) {
		acpi_os_free(temp1);
	}
	if (temp2) {
		acpi_os_free(temp2);
	}
	if (temp3) {
		acpi_os_free(temp3);
	}
	return (status);
}
Пример #22
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);

	/* Parameter validation */

	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 0x%X (%s)",
				    type, acpi_ut_get_type_name(type)));

			return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
		}
	}

	/* Allocate a new field object */

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

	/* Initialize areas of the object that are common to all fields */

	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);
	}

	/* Initialize areas of the object that are specific to the field type */

	switch (info->field_type) {
	case ACPI_TYPE_LOCAL_REGION_FIELD:

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

		/* An additional reference for the container */

		acpi_ut_add_reference(obj_desc->field.region_obj);

		/* allow full data read from EC address space */
		if (obj_desc->field.region_obj->region.space_id ==
			ACPI_ADR_SPACE_EC) {
			if (obj_desc->common_field.bit_length > 8) {
				unsigned width =
					ACPI_ROUND_BITS_UP_TO_BYTES(
					obj_desc->common_field.bit_length);
				// access_bit_width is u8, don't overflow it
				if (width > 8)
					width = 8;
				obj_desc->common_field.access_byte_width =
							width;
				obj_desc->common_field.access_bit_width =
							8 * width;
			}
		}

		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);

		/* An additional reference for the attached objects */

		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));

		/*
		 * Remember location in AML stream of the field unit
		 * opcode and operands -- since the bank_value
		 * operands must be evaluated.
		 */
		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:

		/* Get the Index and Data registers */

		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);
		}

		/* An additional reference for the attached objects */

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

		/*
		 * April 2006: Changed to match MS behavior
		 *
		 * The value written to the Index register is the byte offset of the
		 * target field in units of the granularity of the index_field
		 *
		 * Previously, the value was calculated as an index in terms of the
		 * width of the Data register, as below:
		 *
		 *      obj_desc->index_field.Value = (u32)
		 *          (Info->field_bit_position / ACPI_MUL_8 (
		 *              obj_desc->Field.access_byte_width));
		 *
		 * February 2006: Tried value as a byte offset:
		 *      obj_desc->index_field.Value = (u32)
		 *          ACPI_DIV_8 (Info->field_bit_position);
		 */
		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:
		/* No other types should get here */
		break;
	}

	/*
	 * Store the constructed descriptor (obj_desc) into the parent Node,
	 * preserving the current type of that named_obj.
	 */
	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));

	/* Remove local reference to the object */

	acpi_ut_remove_reference(obj_desc);
	return_ACPI_STATUS(status);
}
Пример #23
0
static ACPI_STATUS
AcpiDbTestOneObject (
    ACPI_HANDLE             ObjHandle,
    UINT32                  NestingLevel,
    void                    *Context,
    void                    **ReturnValue)
{
    ACPI_NAMESPACE_NODE     *Node;
    ACPI_OPERAND_OBJECT     *ObjDesc;
    ACPI_OBJECT_TYPE        LocalType;
    UINT32                  BitLength = 0;
    UINT32                  ByteLength = 0;
    ACPI_STATUS             Status = AE_OK;


    Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle);
    ObjDesc = Node->Object;

    /*
     * For the supported types, get the actual bit length or
     * byte length. Map the type to one of Integer/String/Buffer.
     */
    switch (Node->Type)
    {
    case ACPI_TYPE_INTEGER:

        /* Integer width is either 32 or 64 */

        LocalType = ACPI_TYPE_INTEGER;
        BitLength = AcpiGbl_IntegerBitWidth;
        break;

    case ACPI_TYPE_STRING:

        LocalType = ACPI_TYPE_STRING;
        ByteLength = ObjDesc->String.Length;
        break;

    case ACPI_TYPE_BUFFER:

        LocalType = ACPI_TYPE_BUFFER;
        ByteLength = ObjDesc->Buffer.Length;
        BitLength = ByteLength * 8;
        break;

    case ACPI_TYPE_PACKAGE:

        LocalType = ACPI_TYPE_PACKAGE;
        break;

    case ACPI_TYPE_FIELD_UNIT:
    case ACPI_TYPE_LOCAL_REGION_FIELD:
    case ACPI_TYPE_LOCAL_INDEX_FIELD:
    case ACPI_TYPE_LOCAL_BANK_FIELD:

        LocalType = ACPI_TYPE_FIELD_UNIT;
        break;

    case ACPI_TYPE_BUFFER_FIELD:
        /*
         * The returned object will be a Buffer if the field length
         * is larger than the size of an Integer (32 or 64 bits
         * depending on the DSDT version).
         */
        LocalType = ACPI_TYPE_INTEGER;
        if (ObjDesc)
        {
            BitLength = ObjDesc->CommonField.BitLength;
            ByteLength = ACPI_ROUND_BITS_UP_TO_BYTES (BitLength);
            if (BitLength > AcpiGbl_IntegerBitWidth)
            {
                LocalType = ACPI_TYPE_BUFFER;
            }
        }
        break;

default:

        /* Ignore all non-data types - Methods, Devices, Scopes, etc. */

        return (AE_OK);
    }

    /* Emit the common prefix: Type:Name */

    AcpiOsPrintf ("%14s: %4.4s",
        AcpiUtGetTypeName (Node->Type), Node->Name.Ascii);

    if (!ObjDesc)
    {
        AcpiOsPrintf (" No attached sub-object, ignoring\n");
        return (AE_OK);
    }

    /* At this point, we have resolved the object to one of the major types */

    switch (LocalType)
    {
    case ACPI_TYPE_INTEGER:

        Status = AcpiDbTestIntegerType (Node, BitLength);
        break;

    case ACPI_TYPE_STRING:

        Status = AcpiDbTestStringType (Node, ByteLength);
        break;

    case ACPI_TYPE_BUFFER:

        Status = AcpiDbTestBufferType (Node, BitLength);
        break;

    case ACPI_TYPE_PACKAGE:

        Status = AcpiDbTestPackageType (Node);
        break;

    case ACPI_TYPE_FIELD_UNIT:

        Status = AcpiDbTestFieldUnitType (ObjDesc);
        break;

    default:

        AcpiOsPrintf (" Ignoring, type not implemented (%2.2X)",
            LocalType);
        break;
    }

    /* Exit on error, but don't abort the namespace walk */

    if (ACPI_FAILURE (Status))
    {
        Status = AE_OK;
    }

    AcpiOsPrintf ("\n");
    return (Status);
}
Пример #24
0
acpi_status
acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state,
			     union acpi_operand_object *obj_desc,
			     union acpi_operand_object **ret_buffer_desc)
{
	acpi_status status;
	union acpi_operand_object *buffer_desc;
	acpi_size length;
	void *buffer;
	u32 function;
	u16 accessor_type;

	ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);

	/* Parameter validation */

	if (!obj_desc) {
		return_ACPI_STATUS(AE_AML_NO_OPERAND);
	}
	if (!ret_buffer_desc) {
		return_ACPI_STATUS(AE_BAD_PARAMETER);
	}

	if (obj_desc->common.type == 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);
			}
		}
	} else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
		   (obj_desc->field.region_obj->region.space_id ==
		    ACPI_ADR_SPACE_SMBUS
		    || obj_desc->field.region_obj->region.space_id ==
		    ACPI_ADR_SPACE_GSBUS
		    || obj_desc->field.region_obj->region.space_id ==
		    ACPI_ADR_SPACE_IPMI)) {
		/*
		 * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold
		 * the data and then directly access the region handler.
		 *
		 * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function
		 */
		if (obj_desc->field.region_obj->region.space_id ==
		    ACPI_ADR_SPACE_SMBUS) {
			length = ACPI_SMBUS_BUFFER_SIZE;
			function =
			    ACPI_READ | (obj_desc->field.attribute << 16);
		} else if (obj_desc->field.region_obj->region.space_id ==
			   ACPI_ADR_SPACE_GSBUS) {
			accessor_type = obj_desc->field.attribute;
			length = acpi_ex_get_serial_access_length(accessor_type,
								  obj_desc->
								  field.
								  access_length);

			/*
			 * Add additional 2 bytes for the generic_serial_bus data buffer:
			 *
			 *     Status;      (Byte 0 of the data buffer)
			 *     Length;      (Byte 1 of the data buffer)
			 *     Data[x-1];   (Bytes 2-x of the arbitrary length data buffer)
			 */
			length += 2;
			function = ACPI_READ | (accessor_type << 16);
		} else {	/* IPMI */

			length = ACPI_IPMI_BUFFER_SIZE;
			function = ACPI_READ;
		}

		buffer_desc = acpi_ut_create_buffer_object(length);
		if (!buffer_desc) {
			return_ACPI_STATUS(AE_NO_MEMORY);
		}

		/* Lock entire transaction if requested */

		acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);

		/* Call the region handler for the read */

		status = acpi_ex_access_region(obj_desc, 0,
					       ACPI_CAST_PTR(u64,
							     buffer_desc->
							     buffer.pointer),
					       function);
		acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
		goto exit;
	}

	/*
	 * Allocate a buffer for the contents of the field.
	 *
	 * If the field is larger than the current integer width, create
	 * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
	 * the use of arithmetic operators on the returned value if the
	 * field size is equal or smaller than an Integer.
	 *
	 * Note: Field.length is in bits.
	 */
	length =
	    (acpi_size) ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length);
	if (length > acpi_gbl_integer_byte_width) {

		/* Field is too large for an Integer, create a Buffer instead */

		buffer_desc = acpi_ut_create_buffer_object(length);
		if (!buffer_desc) {
			return_ACPI_STATUS(AE_NO_MEMORY);
		}
		buffer = buffer_desc->buffer.pointer;
	} else {
		/* Field will fit within an Integer (normal case) */

		buffer_desc = acpi_ut_create_integer_object((u64) 0);
		if (!buffer_desc) {
			return_ACPI_STATUS(AE_NO_MEMORY);
		}

		length = acpi_gbl_integer_byte_width;
		buffer = &buffer_desc->integer.value;
	}

	if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
	    (obj_desc->field.region_obj->region.space_id ==
	     ACPI_ADR_SPACE_GPIO)) {
		/*
		 * For GPIO (general_purpose_io), the Address will be the bit offset
		 * from the previous Connection() operator, making it effectively a
		 * pin number index. The bit_length is the length of the field, which
		 * is thus the number of pins.
		 */
		ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
				  "GPIO FieldRead [FROM]:  Pin %u Bits %u\n",
				  obj_desc->field.pin_number_index,
				  obj_desc->field.bit_length));

		/* Lock entire transaction if requested */

		acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);

		/* Perform the write */

		status = acpi_ex_access_region(obj_desc, 0,
					       (u64 *)buffer, ACPI_READ);
		acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
		if (ACPI_FAILURE(status)) {
			acpi_ut_remove_reference(buffer_desc);
		} else {
			*ret_buffer_desc = buffer_desc;
		}
		return_ACPI_STATUS(status);
	}

	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
			  "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
			  obj_desc, obj_desc->common.type, buffer,
			  (u32) length));
	ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
			  "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
			  obj_desc->common_field.bit_length,
			  obj_desc->common_field.start_field_bit_offset,
			  obj_desc->common_field.base_byte_offset));

	/* Lock entire transaction if requested */

	acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);

	/* Read from the field */

	status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length);
	acpi_ex_release_global_lock(obj_desc->common_field.field_flags);

exit:
	if (ACPI_FAILURE(status)) {
		acpi_ut_remove_reference(buffer_desc);
	} else {
		*ret_buffer_desc = buffer_desc;
	}

	return_ACPI_STATUS(status);
}
Пример #25
0
acpi_status
acpi_ex_extract_from_field (
	union acpi_operand_object       *obj_desc,
	void                            *buffer,
	u32                             buffer_length)
{
	acpi_status                     status;
	u32                             field_datum_byte_offset;
	u32                             buffer_datum_offset;
	acpi_integer                    previous_raw_datum = 0;
	acpi_integer                    this_raw_datum = 0;
	acpi_integer                    merged_datum = 0;
	u32                             byte_field_length;
	u32                             datum_count;
	u32                             i;


	ACPI_FUNCTION_TRACE ("ex_extract_from_field");


	/*
	 * The field must fit within the caller's buffer
	 */
	byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length);
	if (byte_field_length > buffer_length) {
		ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
			"Field size %X (bytes) too large for buffer (%X)\n",
			byte_field_length, buffer_length));

		return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
	}

	/* Convert field byte count to datum count, round up if necessary */

	datum_count = ACPI_ROUND_UP_TO (byte_field_length,
			   obj_desc->common_field.access_byte_width);

	/*
	 * If the field is not aligned on a datum boundary and does not
	 * fit within a single datum, we must read an extra datum.
	 *
	 * We could just split the aligned and non-aligned cases since the
	 * aligned case is so very simple, but this would require more code.
	 */
	if ((obj_desc->common_field.end_field_valid_bits != 0)    &&
		(!(obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM))) {
		datum_count++;
	}

	ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
		"byte_len %X, datum_len %X, byte_gran %X\n",
		byte_field_length, datum_count,obj_desc->common_field.access_byte_width));

	/*
	 * Clear the caller's buffer (the whole buffer length as given)
	 * This is very important, especially in the cases where the buffer
	 * is longer than the size of the field.
	 */
	ACPI_MEMSET (buffer, 0, buffer_length);

	field_datum_byte_offset = 0;
	buffer_datum_offset= 0;

	/* Read the entire field */

	for (i = 0; i < datum_count; i++) {
		status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset,
				  &this_raw_datum, ACPI_READ);
		if (ACPI_FAILURE (status)) {
			return_ACPI_STATUS (status);
		}

		/* We might actually be done if the request fits in one datum */

		if ((datum_count == 1) &&
			(obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM)) {
			/* 1) Shift the valid data bits down to start at bit 0 */

			merged_datum = (this_raw_datum >> obj_desc->common_field.start_field_bit_offset);

			/* 2) Mask off any upper unused bits (bits not part of the field) */

			if (obj_desc->common_field.end_buffer_valid_bits) {
				merged_datum &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits);
			}

			/* Store the datum to the caller buffer */

			acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length,
					obj_desc->common_field.access_byte_width, buffer_datum_offset);

			return_ACPI_STATUS (AE_OK);
		}

		/* Special handling for the last datum to ignore extra bits */

		if ((i >= (datum_count -1))          &&
			(obj_desc->common_field.end_field_valid_bits)) {
			/*
			 * This is the last iteration of the loop.  We need to clear
			 * any unused bits (bits that are not part of this field) before
			 * we store the final merged datum into the caller buffer.
			 */
			this_raw_datum &=
				ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits);
		}

		/*
		 * Create the (possibly) merged datum to be stored to the caller buffer
		 */
		if (obj_desc->common_field.start_field_bit_offset == 0) {
			/* Field is not skewed and we can just copy the datum */

			acpi_ex_set_buffer_datum (this_raw_datum, buffer, buffer_length,
					obj_desc->common_field.access_byte_width, buffer_datum_offset);
			buffer_datum_offset++;
		}
		else {
			/* Not aligned -- on the first iteration, just save the datum */

			if (i != 0) {
				/*
				 * Put together the appropriate bits of the two raw data to make a
				 * single complete field datum
				 *
				 * 1) Normalize the first datum down to bit 0
				 */
				merged_datum = (previous_raw_datum >> obj_desc->common_field.start_field_bit_offset);

				/* 2) Insert the second datum "above" the first datum */

				merged_datum |= (this_raw_datum << obj_desc->common_field.datum_valid_bits);

				acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length,
						obj_desc->common_field.access_byte_width, buffer_datum_offset);
				buffer_datum_offset++;
			}

			/*
			 * Save the raw datum that was just acquired since it may contain bits
			 * of the *next* field datum
			 */
			previous_raw_datum = this_raw_datum;
		}