1 /******************************************************************************
3 * Module Name: exfldio - Aml Field I/O
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2016, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
52 #define _COMPONENT ACPI_EXECUTER
53 ACPI_MODULE_NAME ("exfldio")
55 /* Local prototypes */
59 ACPI_OPERAND_OBJECT
*ObjDesc
,
60 UINT32 FieldDatumByteOffset
,
65 AcpiExRegisterOverflow (
66 ACPI_OPERAND_OBJECT
*ObjDesc
,
71 ACPI_OPERAND_OBJECT
*ObjDesc
,
72 UINT32 FieldDatumByteOffset
);
75 /*******************************************************************************
77 * FUNCTION: AcpiExSetupRegion
79 * PARAMETERS: ObjDesc - Field to be read or written
80 * FieldDatumByteOffset - Byte offset of this datum within the
85 * DESCRIPTION: Common processing for AcpiExExtractFromField and
86 * AcpiExInsertIntoField. Initialize the Region if necessary and
87 * validate the request.
89 ******************************************************************************/
93 ACPI_OPERAND_OBJECT
*ObjDesc
,
94 UINT32 FieldDatumByteOffset
)
96 ACPI_STATUS Status
= AE_OK
;
97 ACPI_OPERAND_OBJECT
*RgnDesc
;
101 ACPI_FUNCTION_TRACE_U32 (ExSetupRegion
, FieldDatumByteOffset
);
104 RgnDesc
= ObjDesc
->CommonField
.RegionObj
;
106 /* We must have a valid region */
108 if (RgnDesc
->Common
.Type
!= ACPI_TYPE_REGION
)
110 ACPI_ERROR ((AE_INFO
, "Needed Region, found type 0x%X (%s)",
111 RgnDesc
->Common
.Type
,
112 AcpiUtGetObjectTypeName (RgnDesc
)));
114 return_ACPI_STATUS (AE_AML_OPERAND_TYPE
);
117 SpaceId
= RgnDesc
->Region
.SpaceId
;
119 /* Validate the Space ID */
121 if (!AcpiIsValidSpaceId (SpaceId
))
123 ACPI_ERROR ((AE_INFO
,
124 "Invalid/unknown Address Space ID: 0x%2.2X", SpaceId
));
125 return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID
);
129 * If the Region Address and Length have not been previously evaluated,
130 * evaluate them now and save the results.
132 if (!(RgnDesc
->Common
.Flags
& AOPOBJ_DATA_VALID
))
134 Status
= AcpiDsGetRegionArguments (RgnDesc
);
135 if (ACPI_FAILURE (Status
))
137 return_ACPI_STATUS (Status
);
142 * Exit now for SMBus, GSBus or IPMI address space, it has a non-linear
143 * address space and the request cannot be directly validated
145 if (SpaceId
== ACPI_ADR_SPACE_SMBUS
||
146 SpaceId
== ACPI_ADR_SPACE_GSBUS
||
147 SpaceId
== ACPI_ADR_SPACE_IPMI
)
149 /* SMBus or IPMI has a non-linear address space */
151 return_ACPI_STATUS (AE_OK
);
154 #ifdef ACPI_UNDER_DEVELOPMENT
156 * If the Field access is AnyAcc, we can now compute the optimal
157 * access (because we know know the length of the parent region)
159 if (!(ObjDesc
->Common
.Flags
& AOPOBJ_DATA_VALID
))
161 if (ACPI_FAILURE (Status
))
163 return_ACPI_STATUS (Status
);
169 * Validate the request. The entire request from the byte offset for a
170 * length of one field datum (access width) must fit within the region.
171 * (Region length is specified in bytes)
173 if (RgnDesc
->Region
.Length
<
174 (ObjDesc
->CommonField
.BaseByteOffset
+ FieldDatumByteOffset
+
175 ObjDesc
->CommonField
.AccessByteWidth
))
177 if (AcpiGbl_EnableInterpreterSlack
)
180 * Slack mode only: We will go ahead and allow access to this
181 * field if it is within the region length rounded up to the next
182 * access width boundary. ACPI_SIZE cast for 64-bit compile.
184 if (ACPI_ROUND_UP (RgnDesc
->Region
.Length
,
185 ObjDesc
->CommonField
.AccessByteWidth
) >=
186 ((ACPI_SIZE
) ObjDesc
->CommonField
.BaseByteOffset
+
187 ObjDesc
->CommonField
.AccessByteWidth
+
188 FieldDatumByteOffset
))
190 return_ACPI_STATUS (AE_OK
);
194 if (RgnDesc
->Region
.Length
< ObjDesc
->CommonField
.AccessByteWidth
)
197 * This is the case where the AccessType (AccWord, etc.) is wider
198 * than the region itself. For example, a region of length one
199 * byte, and a field with Dword access specified.
201 ACPI_ERROR ((AE_INFO
,
202 "Field [%4.4s] access width (%u bytes) "
203 "too large for region [%4.4s] (length %u)",
204 AcpiUtGetNodeName (ObjDesc
->CommonField
.Node
),
205 ObjDesc
->CommonField
.AccessByteWidth
,
206 AcpiUtGetNodeName (RgnDesc
->Region
.Node
),
207 RgnDesc
->Region
.Length
));
211 * Offset rounded up to next multiple of field width
212 * exceeds region length, indicate an error
214 ACPI_ERROR ((AE_INFO
,
215 "Field [%4.4s] Base+Offset+Width %u+%u+%u "
216 "is beyond end of region [%4.4s] (length %u)",
217 AcpiUtGetNodeName (ObjDesc
->CommonField
.Node
),
218 ObjDesc
->CommonField
.BaseByteOffset
,
219 FieldDatumByteOffset
, ObjDesc
->CommonField
.AccessByteWidth
,
220 AcpiUtGetNodeName (RgnDesc
->Region
.Node
),
221 RgnDesc
->Region
.Length
));
223 return_ACPI_STATUS (AE_AML_REGION_LIMIT
);
226 return_ACPI_STATUS (AE_OK
);
230 /*******************************************************************************
232 * FUNCTION: AcpiExAccessRegion
234 * PARAMETERS: ObjDesc - Field to be read
235 * FieldDatumByteOffset - Byte offset of this datum within the
237 * Value - Where to store value (must at least
239 * Function - Read or Write flag plus other region-
244 * DESCRIPTION: Read or Write a single field datum to an Operation Region.
246 ******************************************************************************/
250 ACPI_OPERAND_OBJECT
*ObjDesc
,
251 UINT32 FieldDatumByteOffset
,
256 ACPI_OPERAND_OBJECT
*RgnDesc
;
260 ACPI_FUNCTION_TRACE (ExAccessRegion
);
264 * Ensure that the region operands are fully evaluated and verify
265 * the validity of the request
267 Status
= AcpiExSetupRegion (ObjDesc
, FieldDatumByteOffset
);
268 if (ACPI_FAILURE (Status
))
270 return_ACPI_STATUS (Status
);
274 * The physical address of this field datum is:
276 * 1) The base of the region, plus
277 * 2) The base offset of the field, plus
278 * 3) The current offset into the field
280 RgnDesc
= ObjDesc
->CommonField
.RegionObj
;
282 ObjDesc
->CommonField
.BaseByteOffset
+
283 FieldDatumByteOffset
;
285 if ((Function
& ACPI_IO_MASK
) == ACPI_READ
)
287 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
, "[READ]"));
291 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
, "[WRITE]"));
294 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD
,
295 " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
296 AcpiUtGetRegionName (RgnDesc
->Region
.SpaceId
),
297 RgnDesc
->Region
.SpaceId
,
298 ObjDesc
->CommonField
.AccessByteWidth
,
299 ObjDesc
->CommonField
.BaseByteOffset
,
300 FieldDatumByteOffset
,
301 ACPI_FORMAT_UINT64 (RgnDesc
->Region
.Address
+ RegionOffset
)));
303 /* Invoke the appropriate AddressSpace/OpRegion handler */
305 Status
= AcpiEvAddressSpaceDispatch (RgnDesc
, ObjDesc
,
306 Function
, RegionOffset
,
307 ACPI_MUL_8 (ObjDesc
->CommonField
.AccessByteWidth
), Value
);
309 if (ACPI_FAILURE (Status
))
311 if (Status
== AE_NOT_IMPLEMENTED
)
313 ACPI_ERROR ((AE_INFO
,
314 "Region %s (ID=%u) not implemented",
315 AcpiUtGetRegionName (RgnDesc
->Region
.SpaceId
),
316 RgnDesc
->Region
.SpaceId
));
318 else if (Status
== AE_NOT_EXIST
)
320 ACPI_ERROR ((AE_INFO
,
321 "Region %s (ID=%u) has no handler",
322 AcpiUtGetRegionName (RgnDesc
->Region
.SpaceId
),
323 RgnDesc
->Region
.SpaceId
));
327 return_ACPI_STATUS (Status
);
331 /*******************************************************************************
333 * FUNCTION: AcpiExRegisterOverflow
335 * PARAMETERS: ObjDesc - Register(Field) to be written
336 * Value - Value to be stored
338 * RETURN: TRUE if value overflows the field, FALSE otherwise
340 * DESCRIPTION: Check if a value is out of range of the field being written.
341 * Used to check if the values written to Index and Bank registers
342 * are out of range. Normally, the value is simply truncated
343 * to fit the field, but this case is most likely a serious
344 * coding error in the ASL.
346 ******************************************************************************/
349 AcpiExRegisterOverflow (
350 ACPI_OPERAND_OBJECT
*ObjDesc
,
354 if (ObjDesc
->CommonField
.BitLength
>= ACPI_INTEGER_BIT_SIZE
)
357 * The field is large enough to hold the maximum integer, so we can
363 if (Value
>= ((UINT64
) 1 << ObjDesc
->CommonField
.BitLength
))
366 * The Value is larger than the maximum value that can fit into
369 ACPI_ERROR ((AE_INFO
,
370 "Index value 0x%8.8X%8.8X overflows field width 0x%X",
371 ACPI_FORMAT_UINT64 (Value
),
372 ObjDesc
->CommonField
.BitLength
));
377 /* The Value will fit into the field with no truncation */
383 /*******************************************************************************
385 * FUNCTION: AcpiExFieldDatumIo
387 * PARAMETERS: ObjDesc - Field to be read
388 * FieldDatumByteOffset - Byte offset of this datum within the
390 * Value - Where to store value (must be 64 bits)
391 * ReadWrite - Read or Write flag
395 * DESCRIPTION: Read or Write a single datum of a field. The FieldType is
396 * demultiplexed here to handle the different types of fields
397 * (BufferField, RegionField, IndexField, BankField)
399 ******************************************************************************/
403 ACPI_OPERAND_OBJECT
*ObjDesc
,
404 UINT32 FieldDatumByteOffset
,
412 ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo
, FieldDatumByteOffset
);
415 if (ReadWrite
== ACPI_READ
)
421 /* To support reads without saving return value */
425 /* Clear the entire return buffer first, [Very Important!] */
431 * The four types of fields are:
433 * BufferField - Read/write from/to a Buffer
434 * RegionField - Read/write from/to a Operation Region.
435 * BankField - Write to a Bank Register, then read/write from/to an
437 * IndexField - Write to an Index Register, then read/write from/to a
440 switch (ObjDesc
->Common
.Type
)
442 case ACPI_TYPE_BUFFER_FIELD
:
444 * If the BufferField arguments have not been previously evaluated,
445 * evaluate them now and save the results.
447 if (!(ObjDesc
->Common
.Flags
& AOPOBJ_DATA_VALID
))
449 Status
= AcpiDsGetBufferFieldArguments (ObjDesc
);
450 if (ACPI_FAILURE (Status
))
452 return_ACPI_STATUS (Status
);
456 if (ReadWrite
== ACPI_READ
)
459 * Copy the data from the source buffer.
460 * Length is the field width in bytes.
463 (ObjDesc
->BufferField
.BufferObj
)->Buffer
.Pointer
+
464 ObjDesc
->BufferField
.BaseByteOffset
+
465 FieldDatumByteOffset
,
466 ObjDesc
->CommonField
.AccessByteWidth
);
471 * Copy the data to the target buffer.
472 * Length is the field width in bytes.
474 memcpy ((ObjDesc
->BufferField
.BufferObj
)->Buffer
.Pointer
+
475 ObjDesc
->BufferField
.BaseByteOffset
+
476 FieldDatumByteOffset
,
477 Value
, ObjDesc
->CommonField
.AccessByteWidth
);
483 case ACPI_TYPE_LOCAL_BANK_FIELD
:
485 * Ensure that the BankValue is not beyond the capacity of
488 if (AcpiExRegisterOverflow (ObjDesc
->BankField
.BankObj
,
489 (UINT64
) ObjDesc
->BankField
.Value
))
491 return_ACPI_STATUS (AE_AML_REGISTER_LIMIT
);
495 * For BankFields, we must write the BankValue to the BankRegister
496 * (itself a RegionField) before we can access the data.
498 Status
= AcpiExInsertIntoField (ObjDesc
->BankField
.BankObj
,
499 &ObjDesc
->BankField
.Value
,
500 sizeof (ObjDesc
->BankField
.Value
));
501 if (ACPI_FAILURE (Status
))
503 return_ACPI_STATUS (Status
);
507 * Now that the Bank has been selected, fall through to the
508 * RegionField case and write the datum to the Operation Region
511 /*lint -fallthrough */
513 case ACPI_TYPE_LOCAL_REGION_FIELD
:
515 * For simple RegionFields, we just directly access the owning
518 Status
= AcpiExAccessRegion (
519 ObjDesc
, FieldDatumByteOffset
, Value
, ReadWrite
);
522 case ACPI_TYPE_LOCAL_INDEX_FIELD
:
524 * Ensure that the IndexValue is not beyond the capacity of
527 if (AcpiExRegisterOverflow (ObjDesc
->IndexField
.IndexObj
,
528 (UINT64
) ObjDesc
->IndexField
.Value
))
530 return_ACPI_STATUS (AE_AML_REGISTER_LIMIT
);
533 /* Write the index value to the IndexRegister (itself a RegionField) */
535 FieldDatumByteOffset
+= ObjDesc
->IndexField
.Value
;
537 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
538 "Write to Index Register: Value %8.8X\n",
539 FieldDatumByteOffset
));
541 Status
= AcpiExInsertIntoField (ObjDesc
->IndexField
.IndexObj
,
542 &FieldDatumByteOffset
, sizeof (FieldDatumByteOffset
));
543 if (ACPI_FAILURE (Status
))
545 return_ACPI_STATUS (Status
);
548 if (ReadWrite
== ACPI_READ
)
550 /* Read the datum from the DataRegister */
552 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
553 "Read from Data Register\n"));
555 Status
= AcpiExExtractFromField (
556 ObjDesc
->IndexField
.DataObj
, Value
, sizeof (UINT64
));
560 /* Write the datum to the DataRegister */
562 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
563 "Write to Data Register: Value %8.8X%8.8X\n",
564 ACPI_FORMAT_UINT64 (*Value
)));
566 Status
= AcpiExInsertIntoField (
567 ObjDesc
->IndexField
.DataObj
, Value
, sizeof (UINT64
));
573 ACPI_ERROR ((AE_INFO
, "Wrong object type in field I/O %u",
574 ObjDesc
->Common
.Type
));
575 Status
= AE_AML_INTERNAL
;
579 if (ACPI_SUCCESS (Status
))
581 if (ReadWrite
== ACPI_READ
)
583 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
584 "Value Read %8.8X%8.8X, Width %u\n",
585 ACPI_FORMAT_UINT64 (*Value
),
586 ObjDesc
->CommonField
.AccessByteWidth
));
590 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
591 "Value Written %8.8X%8.8X, Width %u\n",
592 ACPI_FORMAT_UINT64 (*Value
),
593 ObjDesc
->CommonField
.AccessByteWidth
));
597 return_ACPI_STATUS (Status
);
601 /*******************************************************************************
603 * FUNCTION: AcpiExWriteWithUpdateRule
605 * PARAMETERS: ObjDesc - Field to be written
606 * Mask - bitmask within field datum
607 * FieldValue - Value to write
608 * FieldDatumByteOffset - Offset of datum within field
612 * DESCRIPTION: Apply the field update rule to a field write
614 ******************************************************************************/
617 AcpiExWriteWithUpdateRule (
618 ACPI_OPERAND_OBJECT
*ObjDesc
,
621 UINT32 FieldDatumByteOffset
)
623 ACPI_STATUS Status
= AE_OK
;
628 ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule
, Mask
);
631 /* Start with the new bits */
633 MergedValue
= FieldValue
;
635 /* If the mask is all ones, we don't need to worry about the update rule */
637 if (Mask
!= ACPI_UINT64_MAX
)
639 /* Decode the update rule */
641 switch (ObjDesc
->CommonField
.FieldFlags
& AML_FIELD_UPDATE_RULE_MASK
)
643 case AML_FIELD_UPDATE_PRESERVE
:
645 * Check if update rule needs to be applied (not if mask is all
646 * ones) The left shift drops the bits we want to ignore.
648 if ((~Mask
<< (ACPI_MUL_8 (sizeof (Mask
)) -
649 ACPI_MUL_8 (ObjDesc
->CommonField
.AccessByteWidth
))) != 0)
652 * Read the current contents of the byte/word/dword containing
653 * the field, and merge with the new field value.
655 Status
= AcpiExFieldDatumIo (
656 ObjDesc
, FieldDatumByteOffset
, &CurrentValue
, ACPI_READ
);
657 if (ACPI_FAILURE (Status
))
659 return_ACPI_STATUS (Status
);
662 MergedValue
|= (CurrentValue
& ~Mask
);
666 case AML_FIELD_UPDATE_WRITE_AS_ONES
:
668 /* Set positions outside the field to all ones */
670 MergedValue
|= ~Mask
;
673 case AML_FIELD_UPDATE_WRITE_AS_ZEROS
:
675 /* Set positions outside the field to all zeros */
682 ACPI_ERROR ((AE_INFO
,
683 "Unknown UpdateRule value: 0x%X",
684 (ObjDesc
->CommonField
.FieldFlags
&
685 AML_FIELD_UPDATE_RULE_MASK
)));
686 return_ACPI_STATUS (AE_AML_OPERAND_VALUE
);
690 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
691 "Mask %8.8X%8.8X, DatumOffset %X, Width %X, "
692 "Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
693 ACPI_FORMAT_UINT64 (Mask
),
694 FieldDatumByteOffset
,
695 ObjDesc
->CommonField
.AccessByteWidth
,
696 ACPI_FORMAT_UINT64 (FieldValue
),
697 ACPI_FORMAT_UINT64 (MergedValue
)));
699 /* Write the merged value */
701 Status
= AcpiExFieldDatumIo (
702 ObjDesc
, FieldDatumByteOffset
, &MergedValue
, ACPI_WRITE
);
704 return_ACPI_STATUS (Status
);
708 /*******************************************************************************
710 * FUNCTION: AcpiExExtractFromField
712 * PARAMETERS: ObjDesc - Field to be read
713 * Buffer - Where to store the field data
714 * BufferLength - Length of Buffer
718 * DESCRIPTION: Retrieve the current value of the given field
720 ******************************************************************************/
723 AcpiExExtractFromField (
724 ACPI_OPERAND_OBJECT
*ObjDesc
,
731 UINT32 FieldOffset
= 0;
732 UINT32 BufferOffset
= 0;
733 UINT32 BufferTailBits
;
735 UINT32 FieldDatumCount
;
736 UINT32 AccessBitWidth
;
740 ACPI_FUNCTION_TRACE (ExExtractFromField
);
743 /* Validate target buffer and clear it */
746 ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc
->CommonField
.BitLength
))
748 ACPI_ERROR ((AE_INFO
,
749 "Field size %u (bits) is too large for buffer (%u)",
750 ObjDesc
->CommonField
.BitLength
, BufferLength
));
752 return_ACPI_STATUS (AE_BUFFER_OVERFLOW
);
755 memset (Buffer
, 0, BufferLength
);
756 AccessBitWidth
= ACPI_MUL_8 (ObjDesc
->CommonField
.AccessByteWidth
);
758 /* Handle the simple case here */
760 if ((ObjDesc
->CommonField
.StartFieldBitOffset
== 0) &&
761 (ObjDesc
->CommonField
.BitLength
== AccessBitWidth
))
763 if (BufferLength
>= sizeof (UINT64
))
765 Status
= AcpiExFieldDatumIo (ObjDesc
, 0, Buffer
, ACPI_READ
);
769 /* Use RawDatum (UINT64) to handle buffers < 64 bits */
771 Status
= AcpiExFieldDatumIo (ObjDesc
, 0, &RawDatum
, ACPI_READ
);
772 memcpy (Buffer
, &RawDatum
, BufferLength
);
775 return_ACPI_STATUS (Status
);
778 /* TBD: Move to common setup code */
780 /* Field algorithm is limited to sizeof(UINT64), truncate if needed */
782 if (ObjDesc
->CommonField
.AccessByteWidth
> sizeof (UINT64
))
784 ObjDesc
->CommonField
.AccessByteWidth
= sizeof (UINT64
);
785 AccessBitWidth
= sizeof (UINT64
) * 8;
788 /* Compute the number of datums (access width data items) */
790 DatumCount
= ACPI_ROUND_UP_TO (
791 ObjDesc
->CommonField
.BitLength
, AccessBitWidth
);
793 FieldDatumCount
= ACPI_ROUND_UP_TO (
794 ObjDesc
->CommonField
.BitLength
+
795 ObjDesc
->CommonField
.StartFieldBitOffset
, AccessBitWidth
);
797 /* Priming read from the field */
799 Status
= AcpiExFieldDatumIo (ObjDesc
, FieldOffset
, &RawDatum
, ACPI_READ
);
800 if (ACPI_FAILURE (Status
))
802 return_ACPI_STATUS (Status
);
804 MergedDatum
= RawDatum
>> ObjDesc
->CommonField
.StartFieldBitOffset
;
806 /* Read the rest of the field */
808 for (i
= 1; i
< FieldDatumCount
; i
++)
810 /* Get next input datum from the field */
812 FieldOffset
+= ObjDesc
->CommonField
.AccessByteWidth
;
813 Status
= AcpiExFieldDatumIo (
814 ObjDesc
, FieldOffset
, &RawDatum
, ACPI_READ
);
815 if (ACPI_FAILURE (Status
))
817 return_ACPI_STATUS (Status
);
821 * Merge with previous datum if necessary.
823 * Note: Before the shift, check if the shift value will be larger than
824 * the integer size. If so, there is no need to perform the operation.
825 * This avoids the differences in behavior between different compilers
826 * concerning shift values larger than the target data width.
828 if (AccessBitWidth
- ObjDesc
->CommonField
.StartFieldBitOffset
<
829 ACPI_INTEGER_BIT_SIZE
)
831 MergedDatum
|= RawDatum
<<
832 (AccessBitWidth
- ObjDesc
->CommonField
.StartFieldBitOffset
);
840 /* Write merged datum to target buffer */
842 memcpy (((char *) Buffer
) + BufferOffset
, &MergedDatum
,
843 ACPI_MIN(ObjDesc
->CommonField
.AccessByteWidth
,
844 BufferLength
- BufferOffset
));
846 BufferOffset
+= ObjDesc
->CommonField
.AccessByteWidth
;
847 MergedDatum
= RawDatum
>> ObjDesc
->CommonField
.StartFieldBitOffset
;
850 /* Mask off any extra bits in the last datum */
852 BufferTailBits
= ObjDesc
->CommonField
.BitLength
% AccessBitWidth
;
855 MergedDatum
&= ACPI_MASK_BITS_ABOVE (BufferTailBits
);
858 /* Write the last datum to the buffer */
860 memcpy (((char *) Buffer
) + BufferOffset
, &MergedDatum
,
861 ACPI_MIN(ObjDesc
->CommonField
.AccessByteWidth
,
862 BufferLength
- BufferOffset
));
864 return_ACPI_STATUS (AE_OK
);
868 /*******************************************************************************
870 * FUNCTION: AcpiExInsertIntoField
872 * PARAMETERS: ObjDesc - Field to be written
873 * Buffer - Data to be written
874 * BufferLength - Length of Buffer
878 * DESCRIPTION: Store the Buffer contents into the given field
880 ******************************************************************************/
883 AcpiExInsertIntoField (
884 ACPI_OPERAND_OBJECT
*ObjDesc
,
894 UINT32 FieldOffset
= 0;
895 UINT32 BufferOffset
= 0;
896 UINT32 BufferTailBits
;
898 UINT32 FieldDatumCount
;
899 UINT32 AccessBitWidth
;
900 UINT32 RequiredLength
;
904 ACPI_FUNCTION_TRACE (ExInsertIntoField
);
907 /* Validate input buffer */
910 RequiredLength
= ACPI_ROUND_BITS_UP_TO_BYTES (
911 ObjDesc
->CommonField
.BitLength
);
914 * We must have a buffer that is at least as long as the field
915 * we are writing to. This is because individual fields are
916 * indivisible and partial writes are not supported -- as per
917 * the ACPI specification.
919 if (BufferLength
< RequiredLength
)
921 /* We need to create a new buffer */
923 NewBuffer
= ACPI_ALLOCATE_ZEROED (RequiredLength
);
926 return_ACPI_STATUS (AE_NO_MEMORY
);
930 * Copy the original data to the new buffer, starting
931 * at Byte zero. All unused (upper) bytes of the
934 memcpy ((char *) NewBuffer
, (char *) Buffer
, BufferLength
);
936 BufferLength
= RequiredLength
;
939 /* TBD: Move to common setup code */
941 /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */
942 if (ObjDesc
->CommonField
.AccessByteWidth
> sizeof (UINT64
))
944 ObjDesc
->CommonField
.AccessByteWidth
= sizeof (UINT64
);
947 AccessBitWidth
= ACPI_MUL_8 (ObjDesc
->CommonField
.AccessByteWidth
);
950 * Create the bitmasks used for bit insertion.
951 * Note: This if/else is used to bypass compiler differences with the
954 if (AccessBitWidth
== ACPI_INTEGER_BIT_SIZE
)
956 WidthMask
= ACPI_UINT64_MAX
;
960 WidthMask
= ACPI_MASK_BITS_ABOVE (AccessBitWidth
);
964 ACPI_MASK_BITS_BELOW (ObjDesc
->CommonField
.StartFieldBitOffset
);
966 /* Compute the number of datums (access width data items) */
968 DatumCount
= ACPI_ROUND_UP_TO (ObjDesc
->CommonField
.BitLength
,
971 FieldDatumCount
= ACPI_ROUND_UP_TO (ObjDesc
->CommonField
.BitLength
+
972 ObjDesc
->CommonField
.StartFieldBitOffset
,
975 /* Get initial Datum from the input buffer */
977 memcpy (&RawDatum
, Buffer
,
978 ACPI_MIN(ObjDesc
->CommonField
.AccessByteWidth
,
979 BufferLength
- BufferOffset
));
981 MergedDatum
= RawDatum
<< ObjDesc
->CommonField
.StartFieldBitOffset
;
983 /* Write the entire field */
985 for (i
= 1; i
< FieldDatumCount
; i
++)
987 /* Write merged datum to the target field */
990 Status
= AcpiExWriteWithUpdateRule (
991 ObjDesc
, Mask
, MergedDatum
, FieldOffset
);
992 if (ACPI_FAILURE (Status
))
997 FieldOffset
+= ObjDesc
->CommonField
.AccessByteWidth
;
1000 * Start new output datum by merging with previous input datum
1003 * Note: Before the shift, check if the shift value will be larger than
1004 * the integer size. If so, there is no need to perform the operation.
1005 * This avoids the differences in behavior between different compilers
1006 * concerning shift values larger than the target data width.
1008 if ((AccessBitWidth
- ObjDesc
->CommonField
.StartFieldBitOffset
) <
1009 ACPI_INTEGER_BIT_SIZE
)
1011 MergedDatum
= RawDatum
>>
1012 (AccessBitWidth
- ObjDesc
->CommonField
.StartFieldBitOffset
);
1021 if (i
== DatumCount
)
1026 /* Get the next input datum from the buffer */
1028 BufferOffset
+= ObjDesc
->CommonField
.AccessByteWidth
;
1029 memcpy (&RawDatum
, ((char *) Buffer
) + BufferOffset
,
1030 ACPI_MIN(ObjDesc
->CommonField
.AccessByteWidth
,
1031 BufferLength
- BufferOffset
));
1033 MergedDatum
|= RawDatum
<< ObjDesc
->CommonField
.StartFieldBitOffset
;
1036 /* Mask off any extra bits in the last datum */
1038 BufferTailBits
= (ObjDesc
->CommonField
.BitLength
+
1039 ObjDesc
->CommonField
.StartFieldBitOffset
) % AccessBitWidth
;
1042 Mask
&= ACPI_MASK_BITS_ABOVE (BufferTailBits
);
1045 /* Write the last datum to the field */
1047 MergedDatum
&= Mask
;
1048 Status
= AcpiExWriteWithUpdateRule (
1049 ObjDesc
, Mask
, MergedDatum
, FieldOffset
);
1052 /* Free temporary buffer if we used one */
1056 ACPI_FREE (NewBuffer
);
1058 return_ACPI_STATUS (Status
);