1 /******************************************************************************
3 * Module Name: exfldio - Aml Field I/O
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2013, 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.
55 #define _COMPONENT ACPI_EXECUTER
56 ACPI_MODULE_NAME ("exfldio")
58 /* Local prototypes */
62 ACPI_OPERAND_OBJECT
*ObjDesc
,
63 UINT32 FieldDatumByteOffset
,
68 AcpiExRegisterOverflow (
69 ACPI_OPERAND_OBJECT
*ObjDesc
,
74 ACPI_OPERAND_OBJECT
*ObjDesc
,
75 UINT32 FieldDatumByteOffset
);
78 /*******************************************************************************
80 * FUNCTION: AcpiExSetupRegion
82 * PARAMETERS: ObjDesc - Field to be read or written
83 * FieldDatumByteOffset - Byte offset of this datum within the
88 * DESCRIPTION: Common processing for AcpiExExtractFromField and
89 * AcpiExInsertIntoField. Initialize the Region if necessary and
90 * validate the request.
92 ******************************************************************************/
96 ACPI_OPERAND_OBJECT
*ObjDesc
,
97 UINT32 FieldDatumByteOffset
)
99 ACPI_STATUS Status
= AE_OK
;
100 ACPI_OPERAND_OBJECT
*RgnDesc
;
104 ACPI_FUNCTION_TRACE_U32 (ExSetupRegion
, FieldDatumByteOffset
);
107 RgnDesc
= ObjDesc
->CommonField
.RegionObj
;
109 /* We must have a valid region */
111 if (RgnDesc
->Common
.Type
!= ACPI_TYPE_REGION
)
113 ACPI_ERROR ((AE_INFO
, "Needed Region, found type 0x%X (%s)",
114 RgnDesc
->Common
.Type
,
115 AcpiUtGetObjectTypeName (RgnDesc
)));
117 return_ACPI_STATUS (AE_AML_OPERAND_TYPE
);
120 SpaceId
= RgnDesc
->Region
.SpaceId
;
122 /* Validate the Space ID */
124 if (!AcpiIsValidSpaceId (SpaceId
))
126 ACPI_ERROR ((AE_INFO
, "Invalid/unknown Address Space ID: 0x%2.2X", SpaceId
));
127 return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID
);
131 * If the Region Address and Length have not been previously evaluated,
132 * evaluate them now and save the results.
134 if (!(RgnDesc
->Common
.Flags
& AOPOBJ_DATA_VALID
))
136 Status
= AcpiDsGetRegionArguments (RgnDesc
);
137 if (ACPI_FAILURE (Status
))
139 return_ACPI_STATUS (Status
);
144 * Exit now for SMBus, GSBus or IPMI address space, it has a non-linear
145 * address space and the request cannot be directly validated
147 if (SpaceId
== ACPI_ADR_SPACE_SMBUS
||
148 SpaceId
== ACPI_ADR_SPACE_GSBUS
||
149 SpaceId
== ACPI_ADR_SPACE_IPMI
)
151 /* SMBus or IPMI has a non-linear address space */
153 return_ACPI_STATUS (AE_OK
);
156 #ifdef ACPI_UNDER_DEVELOPMENT
158 * If the Field access is AnyAcc, we can now compute the optimal
159 * access (because we know know the length of the parent region)
161 if (!(ObjDesc
->Common
.Flags
& AOPOBJ_DATA_VALID
))
163 if (ACPI_FAILURE (Status
))
165 return_ACPI_STATUS (Status
);
171 * Validate the request. The entire request from the byte offset for a
172 * length of one field datum (access width) must fit within the region.
173 * (Region length is specified in bytes)
175 if (RgnDesc
->Region
.Length
<
176 (ObjDesc
->CommonField
.BaseByteOffset
+ FieldDatumByteOffset
+
177 ObjDesc
->CommonField
.AccessByteWidth
))
179 if (AcpiGbl_EnableInterpreterSlack
)
182 * Slack mode only: We will go ahead and allow access to this
183 * field if it is within the region length rounded up to the next
184 * access width boundary. ACPI_SIZE cast for 64-bit compile.
186 if (ACPI_ROUND_UP (RgnDesc
->Region
.Length
,
187 ObjDesc
->CommonField
.AccessByteWidth
) >=
188 ((ACPI_SIZE
) ObjDesc
->CommonField
.BaseByteOffset
+
189 ObjDesc
->CommonField
.AccessByteWidth
+
190 FieldDatumByteOffset
))
192 return_ACPI_STATUS (AE_OK
);
196 if (RgnDesc
->Region
.Length
< ObjDesc
->CommonField
.AccessByteWidth
)
199 * This is the case where the AccessType (AccWord, etc.) is wider
200 * than the region itself. For example, a region of length one
201 * byte, and a field with Dword access specified.
203 ACPI_ERROR ((AE_INFO
,
204 "Field [%4.4s] access width (%u bytes) too large for region [%4.4s] (length %u)",
205 AcpiUtGetNodeName (ObjDesc
->CommonField
.Node
),
206 ObjDesc
->CommonField
.AccessByteWidth
,
207 AcpiUtGetNodeName (RgnDesc
->Region
.Node
),
208 RgnDesc
->Region
.Length
));
212 * Offset rounded up to next multiple of field width
213 * exceeds region length, indicate an error
215 ACPI_ERROR ((AE_INFO
,
216 "Field [%4.4s] Base+Offset+Width %u+%u+%u 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 %p\n",
296 AcpiUtGetRegionName (RgnDesc
->Region
.SpaceId
),
297 RgnDesc
->Region
.SpaceId
,
298 ObjDesc
->CommonField
.AccessByteWidth
,
299 ObjDesc
->CommonField
.BaseByteOffset
,
300 FieldDatumByteOffset
,
301 ACPI_CAST_PTR (void, (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 ACPI_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 (ObjDesc
, FieldDatumByteOffset
, Value
,
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
,
543 sizeof (FieldDatumByteOffset
));
544 if (ACPI_FAILURE (Status
))
546 return_ACPI_STATUS (Status
);
549 if (ReadWrite
== ACPI_READ
)
551 /* Read the datum from the DataRegister */
553 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
554 "Read from Data Register\n"));
556 Status
= AcpiExExtractFromField (ObjDesc
->IndexField
.DataObj
,
557 Value
, sizeof (UINT64
));
561 /* Write the datum to the DataRegister */
563 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
564 "Write to Data Register: Value %8.8X%8.8X\n",
565 ACPI_FORMAT_UINT64 (*Value
)));
567 Status
= AcpiExInsertIntoField (ObjDesc
->IndexField
.DataObj
,
568 Value
, sizeof (UINT64
));
574 ACPI_ERROR ((AE_INFO
, "Wrong object type in field I/O %u",
575 ObjDesc
->Common
.Type
));
576 Status
= AE_AML_INTERNAL
;
580 if (ACPI_SUCCESS (Status
))
582 if (ReadWrite
== ACPI_READ
)
584 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
585 "Value Read %8.8X%8.8X, Width %u\n",
586 ACPI_FORMAT_UINT64 (*Value
),
587 ObjDesc
->CommonField
.AccessByteWidth
));
591 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD
,
592 "Value Written %8.8X%8.8X, Width %u\n",
593 ACPI_FORMAT_UINT64 (*Value
),
594 ObjDesc
->CommonField
.AccessByteWidth
));
598 return_ACPI_STATUS (Status
);
602 /*******************************************************************************
604 * FUNCTION: AcpiExWriteWithUpdateRule
606 * PARAMETERS: ObjDesc - Field to be written
607 * Mask - bitmask within field datum
608 * FieldValue - Value to write
609 * FieldDatumByteOffset - Offset of datum within field
613 * DESCRIPTION: Apply the field update rule to a field write
615 ******************************************************************************/
618 AcpiExWriteWithUpdateRule (
619 ACPI_OPERAND_OBJECT
*ObjDesc
,
622 UINT32 FieldDatumByteOffset
)
624 ACPI_STATUS Status
= AE_OK
;
629 ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule
, Mask
);
632 /* Start with the new bits */
634 MergedValue
= FieldValue
;
636 /* If the mask is all ones, we don't need to worry about the update rule */
638 if (Mask
!= ACPI_UINT64_MAX
)
640 /* Decode the update rule */
642 switch (ObjDesc
->CommonField
.FieldFlags
& AML_FIELD_UPDATE_RULE_MASK
)
644 case AML_FIELD_UPDATE_PRESERVE
:
646 * Check if update rule needs to be applied (not if mask is all
647 * ones) The left shift drops the bits we want to ignore.
649 if ((~Mask
<< (ACPI_MUL_8 (sizeof (Mask
)) -
650 ACPI_MUL_8 (ObjDesc
->CommonField
.AccessByteWidth
))) != 0)
653 * Read the current contents of the byte/word/dword containing
654 * the field, and merge with the new field value.
656 Status
= AcpiExFieldDatumIo (ObjDesc
, FieldDatumByteOffset
,
657 &CurrentValue
, ACPI_READ
);
658 if (ACPI_FAILURE (Status
))
660 return_ACPI_STATUS (Status
);
663 MergedValue
|= (CurrentValue
& ~Mask
);
667 case AML_FIELD_UPDATE_WRITE_AS_ONES
:
669 /* Set positions outside the field to all ones */
671 MergedValue
|= ~Mask
;
674 case AML_FIELD_UPDATE_WRITE_AS_ZEROS
:
676 /* Set positions outside the field to all zeros */
683 ACPI_ERROR ((AE_INFO
,
684 "Unknown UpdateRule value: 0x%X",
685 (ObjDesc
->CommonField
.FieldFlags
& 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, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
692 ACPI_FORMAT_UINT64 (Mask
),
693 FieldDatumByteOffset
,
694 ObjDesc
->CommonField
.AccessByteWidth
,
695 ACPI_FORMAT_UINT64 (FieldValue
),
696 ACPI_FORMAT_UINT64 (MergedValue
)));
698 /* Write the merged value */
700 Status
= AcpiExFieldDatumIo (ObjDesc
, FieldDatumByteOffset
,
701 &MergedValue
, ACPI_WRITE
);
703 return_ACPI_STATUS (Status
);
707 /*******************************************************************************
709 * FUNCTION: AcpiExExtractFromField
711 * PARAMETERS: ObjDesc - Field to be read
712 * Buffer - Where to store the field data
713 * BufferLength - Length of Buffer
717 * DESCRIPTION: Retrieve the current value of the given field
719 ******************************************************************************/
722 AcpiExExtractFromField (
723 ACPI_OPERAND_OBJECT
*ObjDesc
,
730 UINT32 FieldOffset
= 0;
731 UINT32 BufferOffset
= 0;
732 UINT32 BufferTailBits
;
734 UINT32 FieldDatumCount
;
735 UINT32 AccessBitWidth
;
739 ACPI_FUNCTION_TRACE (ExExtractFromField
);
742 /* Validate target buffer and clear it */
745 ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc
->CommonField
.BitLength
))
747 ACPI_ERROR ((AE_INFO
,
748 "Field size %u (bits) is too large for buffer (%u)",
749 ObjDesc
->CommonField
.BitLength
, BufferLength
));
751 return_ACPI_STATUS (AE_BUFFER_OVERFLOW
);
754 ACPI_MEMSET (Buffer
, 0, BufferLength
);
755 AccessBitWidth
= ACPI_MUL_8 (ObjDesc
->CommonField
.AccessByteWidth
);
757 /* Handle the simple case here */
759 if ((ObjDesc
->CommonField
.StartFieldBitOffset
== 0) &&
760 (ObjDesc
->CommonField
.BitLength
== AccessBitWidth
))
762 if (BufferLength
>= sizeof (UINT64
))
764 Status
= AcpiExFieldDatumIo (ObjDesc
, 0, Buffer
, ACPI_READ
);
768 /* Use RawDatum (UINT64) to handle buffers < 64 bits */
770 Status
= AcpiExFieldDatumIo (ObjDesc
, 0, &RawDatum
, ACPI_READ
);
771 ACPI_MEMCPY (Buffer
, &RawDatum
, BufferLength
);
774 return_ACPI_STATUS (Status
);
777 /* TBD: Move to common setup code */
779 /* Field algorithm is limited to sizeof(UINT64), truncate if needed */
781 if (ObjDesc
->CommonField
.AccessByteWidth
> sizeof (UINT64
))
783 ObjDesc
->CommonField
.AccessByteWidth
= sizeof (UINT64
);
784 AccessBitWidth
= sizeof (UINT64
) * 8;
787 /* Compute the number of datums (access width data items) */
789 DatumCount
= ACPI_ROUND_UP_TO (
790 ObjDesc
->CommonField
.BitLength
, AccessBitWidth
);
792 FieldDatumCount
= ACPI_ROUND_UP_TO (
793 ObjDesc
->CommonField
.BitLength
+
794 ObjDesc
->CommonField
.StartFieldBitOffset
, AccessBitWidth
);
796 /* Priming read from the field */
798 Status
= AcpiExFieldDatumIo (ObjDesc
, FieldOffset
, &RawDatum
, ACPI_READ
);
799 if (ACPI_FAILURE (Status
))
801 return_ACPI_STATUS (Status
);
803 MergedDatum
= RawDatum
>> ObjDesc
->CommonField
.StartFieldBitOffset
;
805 /* Read the rest of the field */
807 for (i
= 1; i
< FieldDatumCount
; i
++)
809 /* Get next input datum from the field */
811 FieldOffset
+= ObjDesc
->CommonField
.AccessByteWidth
;
812 Status
= AcpiExFieldDatumIo (ObjDesc
, FieldOffset
,
813 &RawDatum
, ACPI_READ
);
814 if (ACPI_FAILURE (Status
))
816 return_ACPI_STATUS (Status
);
820 * Merge with previous datum if necessary.
822 * Note: Before the shift, check if the shift value will be larger than
823 * the integer size. If so, there is no need to perform the operation.
824 * This avoids the differences in behavior between different compilers
825 * concerning shift values larger than the target data width.
827 if (AccessBitWidth
- ObjDesc
->CommonField
.StartFieldBitOffset
<
828 ACPI_INTEGER_BIT_SIZE
)
830 MergedDatum
|= RawDatum
<<
831 (AccessBitWidth
- ObjDesc
->CommonField
.StartFieldBitOffset
);
839 /* Write merged datum to target buffer */
841 ACPI_MEMCPY (((char *) Buffer
) + BufferOffset
, &MergedDatum
,
842 ACPI_MIN(ObjDesc
->CommonField
.AccessByteWidth
,
843 BufferLength
- BufferOffset
));
845 BufferOffset
+= ObjDesc
->CommonField
.AccessByteWidth
;
846 MergedDatum
= RawDatum
>> ObjDesc
->CommonField
.StartFieldBitOffset
;
849 /* Mask off any extra bits in the last datum */
851 BufferTailBits
= ObjDesc
->CommonField
.BitLength
% AccessBitWidth
;
854 MergedDatum
&= ACPI_MASK_BITS_ABOVE (BufferTailBits
);
857 /* Write the last datum to the buffer */
859 ACPI_MEMCPY (((char *) Buffer
) + BufferOffset
, &MergedDatum
,
860 ACPI_MIN(ObjDesc
->CommonField
.AccessByteWidth
,
861 BufferLength
- BufferOffset
));
863 return_ACPI_STATUS (AE_OK
);
867 /*******************************************************************************
869 * FUNCTION: AcpiExInsertIntoField
871 * PARAMETERS: ObjDesc - Field to be written
872 * Buffer - Data to be written
873 * BufferLength - Length of Buffer
877 * DESCRIPTION: Store the Buffer contents into the given field
879 ******************************************************************************/
882 AcpiExInsertIntoField (
883 ACPI_OPERAND_OBJECT
*ObjDesc
,
893 UINT32 FieldOffset
= 0;
894 UINT32 BufferOffset
= 0;
895 UINT32 BufferTailBits
;
897 UINT32 FieldDatumCount
;
898 UINT32 AccessBitWidth
;
899 UINT32 RequiredLength
;
903 ACPI_FUNCTION_TRACE (ExInsertIntoField
);
906 /* Validate input buffer */
909 RequiredLength
= ACPI_ROUND_BITS_UP_TO_BYTES (
910 ObjDesc
->CommonField
.BitLength
);
912 * We must have a buffer that is at least as long as the field
913 * we are writing to. This is because individual fields are
914 * indivisible and partial writes are not supported -- as per
915 * the ACPI specification.
917 if (BufferLength
< RequiredLength
)
919 /* We need to create a new buffer */
921 NewBuffer
= ACPI_ALLOCATE_ZEROED (RequiredLength
);
924 return_ACPI_STATUS (AE_NO_MEMORY
);
928 * Copy the original data to the new buffer, starting
929 * at Byte zero. All unused (upper) bytes of the
932 ACPI_MEMCPY ((char *) NewBuffer
, (char *) Buffer
, BufferLength
);
934 BufferLength
= RequiredLength
;
937 /* TBD: Move to common setup code */
939 /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */
940 if (ObjDesc
->CommonField
.AccessByteWidth
> sizeof (UINT64
))
942 ObjDesc
->CommonField
.AccessByteWidth
= sizeof (UINT64
);
945 AccessBitWidth
= ACPI_MUL_8 (ObjDesc
->CommonField
.AccessByteWidth
);
948 * Create the bitmasks used for bit insertion.
949 * Note: This if/else is used to bypass compiler differences with the
952 if (AccessBitWidth
== ACPI_INTEGER_BIT_SIZE
)
954 WidthMask
= ACPI_UINT64_MAX
;
958 WidthMask
= ACPI_MASK_BITS_ABOVE (AccessBitWidth
);
962 ACPI_MASK_BITS_BELOW (ObjDesc
->CommonField
.StartFieldBitOffset
);
964 /* Compute the number of datums (access width data items) */
966 DatumCount
= ACPI_ROUND_UP_TO (ObjDesc
->CommonField
.BitLength
,
969 FieldDatumCount
= ACPI_ROUND_UP_TO (ObjDesc
->CommonField
.BitLength
+
970 ObjDesc
->CommonField
.StartFieldBitOffset
,
973 /* Get initial Datum from the input buffer */
975 ACPI_MEMCPY (&RawDatum
, Buffer
,
976 ACPI_MIN(ObjDesc
->CommonField
.AccessByteWidth
,
977 BufferLength
- BufferOffset
));
979 MergedDatum
= RawDatum
<< ObjDesc
->CommonField
.StartFieldBitOffset
;
981 /* Write the entire field */
983 for (i
= 1; i
< FieldDatumCount
; i
++)
985 /* Write merged datum to the target field */
988 Status
= AcpiExWriteWithUpdateRule (ObjDesc
, Mask
,
989 MergedDatum
, FieldOffset
);
990 if (ACPI_FAILURE (Status
))
995 FieldOffset
+= ObjDesc
->CommonField
.AccessByteWidth
;
998 * Start new output datum by merging with previous input datum
1001 * Note: Before the shift, check if the shift value will be larger than
1002 * the integer size. If so, there is no need to perform the operation.
1003 * This avoids the differences in behavior between different compilers
1004 * concerning shift values larger than the target data width.
1006 if ((AccessBitWidth
- ObjDesc
->CommonField
.StartFieldBitOffset
) <
1007 ACPI_INTEGER_BIT_SIZE
)
1009 MergedDatum
= RawDatum
>>
1010 (AccessBitWidth
- ObjDesc
->CommonField
.StartFieldBitOffset
);
1019 if (i
== DatumCount
)
1024 /* Get the next input datum from the buffer */
1026 BufferOffset
+= ObjDesc
->CommonField
.AccessByteWidth
;
1027 ACPI_MEMCPY (&RawDatum
, ((char *) Buffer
) + BufferOffset
,
1028 ACPI_MIN(ObjDesc
->CommonField
.AccessByteWidth
,
1029 BufferLength
- BufferOffset
));
1031 MergedDatum
|= RawDatum
<< ObjDesc
->CommonField
.StartFieldBitOffset
;
1034 /* Mask off any extra bits in the last datum */
1036 BufferTailBits
= (ObjDesc
->CommonField
.BitLength
+
1037 ObjDesc
->CommonField
.StartFieldBitOffset
) % AccessBitWidth
;
1040 Mask
&= ACPI_MASK_BITS_ABOVE (BufferTailBits
);
1043 /* Write the last datum to the field */
1045 MergedDatum
&= Mask
;
1046 Status
= AcpiExWriteWithUpdateRule (ObjDesc
,
1047 Mask
, MergedDatum
, FieldOffset
);
1050 /* Free temporary buffer if we used one */
1054 ACPI_FREE (NewBuffer
);
1056 return_ACPI_STATUS (Status
);