예제 #1
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
        {
예제 #2
0
파일: hwregs.c 프로젝트: alex1818/fwts
ACPI_STATUS
AcpiHwWrite (
    UINT32                  Value,
    ACPI_GENERIC_ADDRESS    *Reg)
{
    UINT64                  Address;
    UINT8                   AccessWidth;
    UINT32                  BitWidth;
    UINT8                   BitOffset;
    UINT64                  Value64;
    UINT32                  NewValue32, OldValue32;
    UINT8                   Index;
    ACPI_STATUS             Status;


    ACPI_FUNCTION_NAME (HwWrite);


    /* Validate contents of the GAS register */

    Status = AcpiHwValidateRegister (Reg, 32, &Address);
    if (ACPI_FAILURE (Status))
    {
        return (Status);
    }

    /* Convert AccessWidth into number of bits based */

    AccessWidth = Reg->AccessWidth ? Reg->AccessWidth : 1;
    AccessWidth = 1 << (AccessWidth + 2);
    BitWidth = ACPI_ROUND_UP (Reg->BitOffset + Reg->BitWidth, AccessWidth);
    BitOffset = Reg->BitOffset;

    /*
     * Two address spaces supported: Memory or IO. PCI_Config is
     * not supported here because the GAS structure is insufficient
     */
    Index = 0;
    while (BitWidth)
    {
        NewValue32 = ACPI_GET_BITS (&Value, (Index * AccessWidth),
            ((1 << AccessWidth) - 1));

        if (BitOffset > AccessWidth)
        {
            BitOffset -= AccessWidth;
        }
        else
        {
            if (BitOffset)
            {
                NewValue32 &= ACPI_MASK_BITS_BELOW (BitOffset);
            }

            if (BitWidth < AccessWidth)
            {
                NewValue32 &= ACPI_MASK_BITS_ABOVE (BitWidth);
            }

            if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
            {
                if (BitOffset || BitWidth < AccessWidth)
                {
                    /*
                     * Read old values in order not to modify the bits that
                     * are beyond the register BitWidth/BitOffset setting.
                     */
                    Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
                        Address + Index * ACPI_DIV_8 (AccessWidth),
                        &Value64, AccessWidth);
                    OldValue32 = (UINT32) Value64;

                    if (BitOffset)
                    {
                        OldValue32 &= ACPI_MASK_BITS_ABOVE (BitOffset + 1);
                        BitOffset = 0;
                    }

                    if (BitWidth < AccessWidth)
                    {
                        OldValue32 &= ACPI_MASK_BITS_BELOW (BitWidth - 1);
                    }

                    NewValue32 |= OldValue32;
                }

                Value64 = (UINT64) NewValue32;
                Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)
                    Address + Index * ACPI_DIV_8 (AccessWidth),
                    Value64, AccessWidth);
            }
            else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
            {
                if (BitOffset || BitWidth < AccessWidth)
                {
                    /*
                     * Read old values in order not to modify the bits that
                     * are beyond the register BitWidth/BitOffset setting.
                     */
                    Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
                        Address + Index * ACPI_DIV_8 (AccessWidth),
                        &OldValue32, AccessWidth);

                    if (BitOffset)
                    {
                        OldValue32 &= ACPI_MASK_BITS_ABOVE (BitOffset + 1);
                        BitOffset = 0;
                    }

                    if (BitWidth < AccessWidth)
                    {
                        OldValue32 &= ACPI_MASK_BITS_BELOW (BitWidth - 1);
                    }

                    NewValue32 |= OldValue32;
                }

                Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
                    Address + Index * ACPI_DIV_8 (AccessWidth),
                    NewValue32, AccessWidth);
            }
        }

        BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth;
        Index++;
    }

    ACPI_DEBUG_PRINT ((ACPI_DB_IO,
        "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
        Value, AccessWidth, ACPI_FORMAT_UINT64 (Address),
        AcpiUtGetRegionName (Reg->SpaceId)));

    return (Status);
}
예제 #3
0
파일: exfldio.c 프로젝트: AiWinters/linux
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 {
예제 #4
0
파일: hwregs.c 프로젝트: alex1818/fwts
ACPI_STATUS
AcpiHwRead (
    UINT32                  *Value,
    ACPI_GENERIC_ADDRESS    *Reg)
{
    UINT64                  Address;
    UINT8                   AccessWidth;
    UINT32                  BitWidth;
    UINT8                   BitOffset;
    UINT64                  Value64;
    UINT32                  Value32;
    UINT8                   Index;
    ACPI_STATUS             Status;


    ACPI_FUNCTION_NAME (HwRead);


    /* Validate contents of the GAS register */

    Status = AcpiHwValidateRegister (Reg, 32, &Address);
    if (ACPI_FAILURE (Status))
    {
        return (Status);
    }

    /*
     * Initialize entire 32-bit return value to zero, convert AccessWidth
     * into number of bits based
     */
    *Value = 0;
    AccessWidth = Reg->AccessWidth ? Reg->AccessWidth : 1;
    AccessWidth = 1 << (AccessWidth + 2);
    BitWidth = ACPI_ROUND_UP (Reg->BitOffset + Reg->BitWidth, AccessWidth);
    BitOffset = Reg->BitOffset;

    /*
     * Two address spaces supported: Memory or IO. PCI_Config is
     * not supported here because the GAS structure is insufficient
     */
    Index = 0;
    while (BitWidth)
    {
        if (BitOffset > AccessWidth)
        {
            Value32 = 0;
            BitOffset -= AccessWidth;
        }
        else
        {
            if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
            {
                Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
                    Address + Index * ACPI_DIV_8 (AccessWidth),
                    &Value64, AccessWidth);
                Value32 = (UINT32) Value64;
            }
            else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
            {
                Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
                    Address + Index * ACPI_DIV_8 (AccessWidth),
                    &Value32, AccessWidth);
            }

            if (BitOffset)
            {
                Value32 &= ACPI_MASK_BITS_BELOW (BitOffset);
                BitOffset = 0;
            }
            if (BitWidth < AccessWidth)
            {
                Value32 &= ACPI_MASK_BITS_ABOVE (BitWidth);
            }
        }

        ACPI_SET_BITS (Value, Index * AccessWidth,
            ((1 << AccessWidth) - 1), Value32);

        BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth;
        Index++;
    }

    ACPI_DEBUG_PRINT ((ACPI_DB_IO,
        "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
        *Value, AccessWidth, ACPI_FORMAT_UINT64 (Address),
        AcpiUtGetRegionName (Reg->SpaceId)));

    return (Status);
}
예제 #5
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);
}
예제 #6
0
파일: hwregs.c 프로젝트: AngleFork/linux
acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
{
	u64 address;
	u8 access_width;
	u32 bit_width;
	u8 bit_offset;
	u64 value64;
	u32 new_value32, old_value32;
	u8 index;
	acpi_status status;

	ACPI_FUNCTION_NAME(hw_write);

	/* Validate contents of the GAS register */

	status = acpi_hw_validate_register(reg, 32, &address);
	if (ACPI_FAILURE(status)) {
		return (status);
	}

	/* Convert access_width into number of bits based */

	access_width = acpi_hw_get_access_bit_width(reg, 32);
	bit_width = reg->bit_offset + reg->bit_width;
	bit_offset = reg->bit_offset;

	/*
	 * Two address spaces supported: Memory or IO. PCI_Config is
	 * not supported here because the GAS structure is insufficient
	 */
	index = 0;
	while (bit_width) {
		/*
		 * Use offset style bit reads because "Index * AccessWidth" is
		 * ensured to be less than 32-bits by acpi_hw_validate_register().
		 */
		new_value32 = ACPI_GET_BITS(&value, index * access_width,
					    ACPI_MASK_BITS_ABOVE_32
					    (access_width));

		if (bit_offset >= access_width) {
			bit_offset -= access_width;
		} else {
			/*
			 * Use offset style bit masks because access_width is ensured
			 * to be less than 32-bits by acpi_hw_validate_register() and
			 * bit_offset/bit_width is less than access_width here.
			 */
			if (bit_offset) {
				new_value32 &= ACPI_MASK_BITS_BELOW(bit_offset);
			}
			if (bit_width < access_width) {
				new_value32 &= ACPI_MASK_BITS_ABOVE(bit_width);
			}

			if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
				if (bit_offset || bit_width < access_width) {
					/*
					 * Read old values in order not to modify the bits that
					 * are beyond the register bit_width/bit_offset setting.
					 */
					status =
					    acpi_os_read_memory((acpi_physical_address)
								address +
								index *
								ACPI_DIV_8
								(access_width),
								&value64,
								access_width);
					old_value32 = (u32)value64;

					/*
					 * Use offset style bit masks because access_width is
					 * ensured to be less than 32-bits by
					 * acpi_hw_validate_register() and bit_offset/bit_width is
					 * less than access_width here.
					 */
					if (bit_offset) {
						old_value32 &=
						    ACPI_MASK_BITS_ABOVE
						    (bit_offset);
						bit_offset = 0;
					}
					if (bit_width < access_width) {
						old_value32 &=
						    ACPI_MASK_BITS_BELOW
						    (bit_width);
					}

					new_value32 |= old_value32;
				}

				value64 = (u64)new_value32;
				status =
				    acpi_os_write_memory((acpi_physical_address)
							 address +
							 index *
							 ACPI_DIV_8
							 (access_width),
							 value64, access_width);
			} else {	/* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */

				if (bit_offset || bit_width < access_width) {
					/*
					 * Read old values in order not to modify the bits that
					 * are beyond the register bit_width/bit_offset setting.
					 */
					status =
					    acpi_hw_read_port((acpi_io_address)
							      address +
							      index *
							      ACPI_DIV_8
							      (access_width),
							      &old_value32,
							      access_width);

					/*
					 * Use offset style bit masks because access_width is
					 * ensured to be less than 32-bits by
					 * acpi_hw_validate_register() and bit_offset/bit_width is
					 * less than access_width here.
					 */
					if (bit_offset) {
						old_value32 &=
						    ACPI_MASK_BITS_ABOVE
						    (bit_offset);
						bit_offset = 0;
					}
					if (bit_width < access_width) {
						old_value32 &=
						    ACPI_MASK_BITS_BELOW
						    (bit_width);
					}

					new_value32 |= old_value32;
				}

				status = acpi_hw_write_port((acpi_io_address)
							    address +
							    index *
							    ACPI_DIV_8
							    (access_width),
							    new_value32,
							    access_width);
			}
		}

		/*
		 * Index * access_width is ensured to be less than 32-bits by
		 * acpi_hw_validate_register().
		 */
		bit_width -=
		    bit_width > access_width ? access_width : bit_width;
		index++;
	}

	ACPI_DEBUG_PRINT((ACPI_DB_IO,
			  "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
			  value, access_width, ACPI_FORMAT_UINT64(address),
			  acpi_ut_get_region_name(reg->space_id)));

	return (status);
}
예제 #7
0
파일: hwregs.c 프로젝트: AngleFork/linux
acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
{
	u64 address;
	u8 access_width;
	u32 bit_width;
	u8 bit_offset;
	u64 value64;
	u32 value32;
	u8 index;
	acpi_status status;

	ACPI_FUNCTION_NAME(hw_read);

	/* Validate contents of the GAS register */

	status = acpi_hw_validate_register(reg, 32, &address);
	if (ACPI_FAILURE(status)) {
		return (status);
	}

	/*
	 * Initialize entire 32-bit return value to zero, convert access_width
	 * into number of bits based
	 */
	*value = 0;
	access_width = acpi_hw_get_access_bit_width(reg, 32);
	bit_width = reg->bit_offset + reg->bit_width;
	bit_offset = reg->bit_offset;

	/*
	 * Two address spaces supported: Memory or IO. PCI_Config is
	 * not supported here because the GAS structure is insufficient
	 */
	index = 0;
	while (bit_width) {
		if (bit_offset >= access_width) {
			value32 = 0;
			bit_offset -= access_width;
		} else {
			if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
				status =
				    acpi_os_read_memory((acpi_physical_address)
							address +
							index *
							ACPI_DIV_8
							(access_width),
							&value64, access_width);
				value32 = (u32)value64;
			} else {	/* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */

				status = acpi_hw_read_port((acpi_io_address)
							   address +
							   index *
							   ACPI_DIV_8
							   (access_width),
							   &value32,
							   access_width);
			}

			/*
			 * Use offset style bit masks because:
			 * bit_offset < access_width/bit_width < access_width, and
			 * access_width is ensured to be less than 32-bits by
			 * acpi_hw_validate_register().
			 */
			if (bit_offset) {
				value32 &= ACPI_MASK_BITS_BELOW(bit_offset);
				bit_offset = 0;
			}
			if (bit_width < access_width) {
				value32 &= ACPI_MASK_BITS_ABOVE(bit_width);
			}
		}

		/*
		 * Use offset style bit writes because "Index * AccessWidth" is
		 * ensured to be less than 32-bits by acpi_hw_validate_register().
		 */
		ACPI_SET_BITS(value, index * access_width,
			      ACPI_MASK_BITS_ABOVE_32(access_width), value32);

		bit_width -=
		    bit_width > access_width ? access_width : bit_width;
		index++;
	}

	ACPI_DEBUG_PRINT((ACPI_DB_IO,
			  "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
			  *value, access_width, ACPI_FORMAT_UINT64(address),
			  acpi_ut_get_region_name(reg->space_id)));

	return (status);
}
예제 #8
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 {