diff options
Diffstat (limited to 'sys/contrib/dev/acpica/exfldio.c')
| -rw-r--r-- | sys/contrib/dev/acpica/exfldio.c | 692 |
1 files changed, 201 insertions, 491 deletions
diff --git a/sys/contrib/dev/acpica/exfldio.c b/sys/contrib/dev/acpica/exfldio.c index 3b56738643be..efd1decdd464 100644 --- a/sys/contrib/dev/acpica/exfldio.c +++ b/sys/contrib/dev/acpica/exfldio.c @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: exfldio - Aml Field I/O - * $Revision: 111 $ + * $Revision: 1.116 $ * *****************************************************************************/ @@ -9,7 +9,7 @@ * * 1. Copyright Notice * - * Some or all of this work - Copyright (c) 1999 - 2004, Intel Corp. + * Some or all of this work - Copyright (c) 1999 - 2005, Intel Corp. * All rights reserved. * * 2. License @@ -127,12 +127,31 @@ #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exfldio") +/* Local prototypes */ + +static ACPI_STATUS +AcpiExFieldDatumIo ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 FieldDatumByteOffset, + ACPI_INTEGER *Value, + UINT32 ReadWrite); + +static BOOLEAN +AcpiExRegisterOverflow ( + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_INTEGER Value); + +static ACPI_STATUS +AcpiExSetupRegion ( + ACPI_OPERAND_OBJECT *ObjDesc, + UINT32 FieldDatumByteOffset); + /******************************************************************************* * * FUNCTION: AcpiExSetupRegion * - * PARAMETERS: *ObjDesc - Field to be read or written + * PARAMETERS: ObjDesc - Field to be read or written * FieldDatumByteOffset - Byte offset of this datum within the * parent field * @@ -144,7 +163,7 @@ * ******************************************************************************/ -ACPI_STATUS +static ACPI_STATUS AcpiExSetupRegion ( ACPI_OPERAND_OBJECT *ObjDesc, UINT32 FieldDatumByteOffset) @@ -208,9 +227,9 @@ AcpiExSetupRegion ( * length of one field datum (access width) must fit within the region. * (Region length is specified in bytes) */ - if (RgnDesc->Region.Length < (ObjDesc->CommonField.BaseByteOffset - + FieldDatumByteOffset - + ObjDesc->CommonField.AccessByteWidth)) + if (RgnDesc->Region.Length < (ObjDesc->CommonField.BaseByteOffset + + FieldDatumByteOffset + + ObjDesc->CommonField.AccessByteWidth)) { if (AcpiGbl_EnableInterpreterSlack) { @@ -240,7 +259,8 @@ AcpiExSetupRegion ( "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n", AcpiUtGetNodeName (ObjDesc->CommonField.Node), ObjDesc->CommonField.AccessByteWidth, - AcpiUtGetNodeName (RgnDesc->Region.Node), RgnDesc->Region.Length)); + AcpiUtGetNodeName (RgnDesc->Region.Node), + RgnDesc->Region.Length)); } /* @@ -252,7 +272,8 @@ AcpiExSetupRegion ( AcpiUtGetNodeName (ObjDesc->CommonField.Node), ObjDesc->CommonField.BaseByteOffset, FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth, - AcpiUtGetNodeName (RgnDesc->Region.Node), RgnDesc->Region.Length)); + AcpiUtGetNodeName (RgnDesc->Region.Node), + RgnDesc->Region.Length)); return_ACPI_STATUS (AE_AML_REGION_LIMIT); } @@ -265,10 +286,10 @@ AcpiExSetupRegion ( * * FUNCTION: AcpiExAccessRegion * - * PARAMETERS: *ObjDesc - Field to be read + * PARAMETERS: ObjDesc - Field to be read * FieldDatumByteOffset - Byte offset of this datum within the * parent field - * *Value - Where to store value (must at least + * Value - Where to store value (must at least * the size of ACPI_INTEGER) * Function - Read or Write flag plus other region- * dependent flags @@ -312,9 +333,9 @@ AcpiExAccessRegion ( * 3) The current offset into the field */ RgnDesc = ObjDesc->CommonField.RegionObj; - Address = RgnDesc->Region.Address - + ObjDesc->CommonField.BaseByteOffset - + FieldDatumByteOffset; + Address = RgnDesc->Region.Address + + ObjDesc->CommonField.BaseByteOffset + + FieldDatumByteOffset; if ((Function & ACPI_IO_MASK) == ACPI_READ) { @@ -337,7 +358,8 @@ AcpiExAccessRegion ( /* Invoke the appropriate AddressSpace/OpRegion handler */ Status = AcpiEvAddressSpaceDispatch (RgnDesc, Function, - Address, ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value); + Address, + ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value); if (ACPI_FAILURE (Status)) { @@ -365,7 +387,7 @@ AcpiExAccessRegion ( * * FUNCTION: AcpiExRegisterOverflow * - * PARAMETERS: *ObjDesc - Register(Field) to be written + * PARAMETERS: ObjDesc - Register(Field) to be written * Value - Value to be stored * * RETURN: TRUE if value overflows the field, FALSE otherwise @@ -378,7 +400,7 @@ AcpiExAccessRegion ( * ******************************************************************************/ -BOOLEAN +static BOOLEAN AcpiExRegisterOverflow ( ACPI_OPERAND_OBJECT *ObjDesc, ACPI_INTEGER Value) @@ -412,10 +434,10 @@ AcpiExRegisterOverflow ( * * FUNCTION: AcpiExFieldDatumIo * - * PARAMETERS: *ObjDesc - Field to be read + * PARAMETERS: ObjDesc - Field to be read * FieldDatumByteOffset - Byte offset of this datum within the * parent field - * *Value - Where to store value (must be 64 bits) + * Value - Where to store value (must be 64 bits) * ReadWrite - Read or Write flag * * RETURN: Status @@ -426,7 +448,7 @@ AcpiExRegisterOverflow ( * ******************************************************************************/ -ACPI_STATUS +static ACPI_STATUS AcpiExFieldDatumIo ( ACPI_OPERAND_OBJECT *ObjDesc, UINT32 FieldDatumByteOffset, @@ -445,7 +467,9 @@ AcpiExFieldDatumIo ( if (!Value) { LocalValue = 0; - Value = &LocalValue; /* To support reads without saving return value */ + + /* To support reads without saving return value */ + Value = &LocalValue; } /* Clear the entire return buffer first, [Very Important!] */ @@ -458,8 +482,10 @@ AcpiExFieldDatumIo ( * * BufferField - Read/write from/to a Buffer * RegionField - Read/write from/to a Operation Region. - * BankField - Write to a Bank Register, then read/write from/to an OpRegion - * IndexField - Write to an Index Register, then read/write from/to a Data Register + * BankField - Write to a Bank Register, then read/write from/to an + * OperationRegion + * IndexField - Write to an Index Register, then read/write from/to a + * Data Register */ switch (ACPI_GET_OBJECT_TYPE (ObjDesc)) { @@ -483,10 +509,11 @@ AcpiExFieldDatumIo ( * Copy the data from the source buffer. * Length is the field width in bytes. */ - ACPI_MEMCPY (Value, (ObjDesc->BufferField.BufferObj)->Buffer.Pointer - + ObjDesc->BufferField.BaseByteOffset - + FieldDatumByteOffset, - ObjDesc->CommonField.AccessByteWidth); + ACPI_MEMCPY (Value, + (ObjDesc->BufferField.BufferObj)->Buffer.Pointer + + ObjDesc->BufferField.BaseByteOffset + + FieldDatumByteOffset, + ObjDesc->CommonField.AccessByteWidth); } else { @@ -494,9 +521,9 @@ AcpiExFieldDatumIo ( * Copy the data to the target buffer. * Length is the field width in bytes. */ - ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer - + ObjDesc->BufferField.BaseByteOffset - + FieldDatumByteOffset, + ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer + + ObjDesc->BufferField.BaseByteOffset + + FieldDatumByteOffset, Value, ObjDesc->CommonField.AccessByteWidth); } @@ -506,8 +533,10 @@ AcpiExFieldDatumIo ( case ACPI_TYPE_LOCAL_BANK_FIELD: - /* Ensure that the BankValue is not beyond the capacity of the register */ - + /* + * Ensure that the BankValue is not beyond the capacity of + * the register + */ if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj, (ACPI_INTEGER) ObjDesc->BankField.Value)) { @@ -547,8 +576,10 @@ AcpiExFieldDatumIo ( case ACPI_TYPE_LOCAL_INDEX_FIELD: - /* Ensure that the IndexValue is not beyond the capacity of the register */ - + /* + * Ensure that the IndexValue is not beyond the capacity of + * the register + */ if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj, (ACPI_INTEGER) ObjDesc->IndexField.Value)) { @@ -604,15 +635,17 @@ AcpiExFieldDatumIo ( { if (ReadWrite == ACPI_READ) { - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read %8.8X%8.8X, Width %d\n", - ACPI_FORMAT_UINT64 (*Value), - ObjDesc->CommonField.AccessByteWidth)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Value Read %8.8X%8.8X, Width %d\n", + ACPI_FORMAT_UINT64 (*Value), + ObjDesc->CommonField.AccessByteWidth)); } else { - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written %8.8X%8.8X, Width %d\n", - ACPI_FORMAT_UINT64 (*Value), - ObjDesc->CommonField.AccessByteWidth)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Value Written %8.8X%8.8X, Width %d\n", + ACPI_FORMAT_UINT64 (*Value), + ObjDesc->CommonField.AccessByteWidth)); } } @@ -624,8 +657,10 @@ AcpiExFieldDatumIo ( * * FUNCTION: AcpiExWriteWithUpdateRule * - * PARAMETERS: *ObjDesc - Field to be set - * Value - Value to store + * PARAMETERS: ObjDesc - Field to be written + * Mask - bitmask within field datum + * FieldValue - Value to write + * FieldDatumByteOffset - Offset of datum within field * * RETURN: Status * @@ -725,213 +760,6 @@ AcpiExWriteWithUpdateRule ( /******************************************************************************* * - * FUNCTION: AcpiExGetBufferDatum - * - * PARAMETERS: Datum - Where the Datum is returned - * Buffer - Raw field buffer - * BufferLength - Entire length (used for big-endian only) - * ByteGranularity - 1/2/4/8 Granularity of the field - * (aka Datum Size) - * BufferOffset - Datum offset into the buffer - * - * RETURN: none - * - * DESCRIPTION: Get a datum from the buffer according to the buffer field - * byte granularity - * - ******************************************************************************/ - -void -AcpiExGetBufferDatum ( - ACPI_INTEGER *Datum, - void *Buffer, - UINT32 BufferLength, - UINT32 ByteGranularity, - UINT32 BufferOffset) -{ - UINT32 Index; - - - ACPI_FUNCTION_TRACE_U32 ("ExGetBufferDatum", ByteGranularity); - - - /* Get proper index into buffer (handles big/little endian) */ - - Index = ACPI_BUFFER_INDEX (BufferLength, BufferOffset, ByteGranularity); - - /* Move the requested number of bytes */ - - switch (ByteGranularity) - { - case ACPI_FIELD_BYTE_GRANULARITY: - - *Datum = ((UINT8 *) Buffer) [Index]; - break; - - case ACPI_FIELD_WORD_GRANULARITY: - - ACPI_MOVE_16_TO_64 (Datum, &(((UINT16 *) Buffer) [Index])); - break; - - case ACPI_FIELD_DWORD_GRANULARITY: - - ACPI_MOVE_32_TO_64 (Datum, &(((UINT32 *) Buffer) [Index])); - break; - - case ACPI_FIELD_QWORD_GRANULARITY: - - ACPI_MOVE_64_TO_64 (Datum, &(((UINT64 *) Buffer) [Index])); - break; - - default: - /* Should not get here */ - break; - } - - return_VOID; -} - - -/******************************************************************************* - * - * FUNCTION: AcpiExSetBufferDatum - * - * PARAMETERS: MergedDatum - Value to store - * Buffer - Receiving buffer - * BufferLength - Entire length (used for big-endian only) - * ByteGranularity - 1/2/4/8 Granularity of the field - * (aka Datum Size) - * BufferOffset - Datum offset into the buffer - * - * RETURN: none - * - * DESCRIPTION: Store the merged datum to the buffer according to the - * byte granularity - * - ******************************************************************************/ - -void -AcpiExSetBufferDatum ( - ACPI_INTEGER MergedDatum, - void *Buffer, - UINT32 BufferLength, - UINT32 ByteGranularity, - UINT32 BufferOffset) -{ - UINT32 Index; - - - ACPI_FUNCTION_TRACE_U32 ("ExSetBufferDatum", ByteGranularity); - - - /* Get proper index into buffer (handles big/little endian) */ - - Index = ACPI_BUFFER_INDEX (BufferLength, BufferOffset, ByteGranularity); - - /* Move the requested number of bytes */ - - switch (ByteGranularity) - { - case ACPI_FIELD_BYTE_GRANULARITY: - - ((UINT8 *) Buffer) [Index] = (UINT8) MergedDatum; - break; - - case ACPI_FIELD_WORD_GRANULARITY: - - ACPI_MOVE_64_TO_16 (&(((UINT16 *) Buffer)[Index]), &MergedDatum); - break; - - case ACPI_FIELD_DWORD_GRANULARITY: - - ACPI_MOVE_64_TO_32 (&(((UINT32 *) Buffer)[Index]), &MergedDatum); - break; - - case ACPI_FIELD_QWORD_GRANULARITY: - - ACPI_MOVE_64_TO_64 (&(((UINT64 *) Buffer)[Index]), &MergedDatum); - break; - - default: - /* Should not get here */ - break; - } - - return_VOID; -} - - -/******************************************************************************* - * - * FUNCTION: AcpiExCommonBufferSetup - * - * PARAMETERS: ObjDesc - Field object - * BufferLength - Length of caller's buffer - * DatumCount - Where the DatumCount is returned - * - * RETURN: Status, DatumCount - * - * DESCRIPTION: Common code to validate the incoming buffer size and compute - * the number of field "datums" that must be read or written. - * A "datum" is the smallest unit that can be read or written - * to the field, it is either 1,2,4, or 8 bytes. - * - ******************************************************************************/ - -ACPI_STATUS -AcpiExCommonBufferSetup ( - ACPI_OPERAND_OBJECT *ObjDesc, - UINT32 BufferLength, - UINT32 *DatumCount) -{ - UINT32 ByteFieldLength; - UINT32 ActualByteFieldLength; - - - ACPI_FUNCTION_TRACE ("ExCommonBufferSetup"); - - - /* - * Incoming buffer must be at least as long as the field, we do not - * allow "partial" field reads/writes. We do not care if the buffer is - * larger than the field, this typically happens when an integer is - * read/written to a field that is actually smaller than an integer. - */ - ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES ( - ObjDesc->CommonField.BitLength); - if (ByteFieldLength > BufferLength) - { - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "Field size %X (bytes) is too large for buffer (%X)\n", - ByteFieldLength, BufferLength)); - - return_ACPI_STATUS (AE_BUFFER_OVERFLOW); - } - - /* - * Create "actual" field byte count (minimum number of bytes that - * must be read), then convert to datum count (minimum number - * of datum-sized units that must be read) - */ - ActualByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES ( - ObjDesc->CommonField.StartFieldBitOffset + - ObjDesc->CommonField.BitLength); - - - *DatumCount = ACPI_ROUND_UP_TO (ActualByteFieldLength, - ObjDesc->CommonField.AccessByteWidth); - - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "BufferBytes %X, ActualBytes %X, Datums %X, ByteGran %X\n", - ByteFieldLength, ActualByteFieldLength, - *DatumCount, ObjDesc->CommonField.AccessByteWidth)); - - return_ACPI_STATUS (AE_OK); -} - - -/******************************************************************************* - * * FUNCTION: AcpiExExtractFromField * * PARAMETERS: ObjDesc - Field to be read @@ -951,139 +779,101 @@ AcpiExExtractFromField ( UINT32 BufferLength) { ACPI_STATUS Status; - UINT32 FieldDatumByteOffset; - UINT32 BufferDatumOffset; - ACPI_INTEGER PreviousRawDatum = 0; - ACPI_INTEGER ThisRawDatum = 0; - ACPI_INTEGER MergedDatum = 0; + ACPI_INTEGER RawDatum; + ACPI_INTEGER MergedDatum; + UINT32 FieldOffset = 0; + UINT32 BufferOffset = 0; + UINT32 BufferTailBits; UINT32 DatumCount; + UINT32 FieldDatumCount; UINT32 i; ACPI_FUNCTION_TRACE ("ExExtractFromField"); - /* Validate buffer, compute number of datums */ + /* Validate target buffer and clear it */ - Status = AcpiExCommonBufferSetup (ObjDesc, BufferLength, &DatumCount); - if (ACPI_FAILURE (Status)) + if (BufferLength < ACPI_ROUND_BITS_UP_TO_BYTES ( + ObjDesc->CommonField.BitLength)) { - return_ACPI_STATUS (Status); - } + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Field size %X (bits) is too large for buffer (%X)\n", + ObjDesc->CommonField.BitLength, BufferLength)); - /* - * 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. - */ + return_ACPI_STATUS (AE_BUFFER_OVERFLOW); + } ACPI_MEMSET (Buffer, 0, BufferLength); - FieldDatumByteOffset = 0; - BufferDatumOffset= 0; - - /* Read the entire field */ - - for (i = 0; i < DatumCount; i++) - { - Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, - &ThisRawDatum, ACPI_READ); - if (ACPI_FAILURE (Status)) - { - return_ACPI_STATUS (Status); - } - - /* We might actually be done if the request fits in one datum */ - - if ((DatumCount == 1) && - (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM)) - { - /* 1) Shift the valid data bits down to start at bit 0 */ + /* Compute the number of datums (access width data items) */ - MergedDatum = (ThisRawDatum >> ObjDesc->CommonField.StartFieldBitOffset); + DatumCount = ACPI_ROUND_UP_TO ( + ObjDesc->CommonField.BitLength, + ObjDesc->CommonField.AccessBitWidth); + FieldDatumCount = ACPI_ROUND_UP_TO ( + ObjDesc->CommonField.BitLength + + ObjDesc->CommonField.StartFieldBitOffset, + ObjDesc->CommonField.AccessBitWidth); - /* 2) Mask off any upper unused bits (bits not part of the field) */ + /* Priming read from the field */ - if (ObjDesc->CommonField.EndBufferValidBits) - { - MergedDatum &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits); - } + Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; - /* Store the datum to the caller buffer */ + /* Read the rest of the field */ - AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength, - ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset); + for (i = 1; i < FieldDatumCount; i++) + { + /* Get next input datum from the field */ - return_ACPI_STATUS (AE_OK); + FieldOffset += ObjDesc->CommonField.AccessByteWidth; + Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, + &RawDatum, ACPI_READ); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); } - /* Special handling for the last datum to ignore extra bits */ + /* Merge with previous datum if necessary */ - if ((i >= (DatumCount -1)) && - (ObjDesc->CommonField.EndFieldValidBits)) - { - /* - * 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. - */ - ThisRawDatum &= - ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits); - } + MergedDatum |= RawDatum << + (ObjDesc->CommonField.AccessBitWidth - + ObjDesc->CommonField.StartFieldBitOffset); - /* - * Create the (possibly) merged datum to be stored to the caller buffer - */ - if (ObjDesc->CommonField.StartFieldBitOffset == 0) + if (i == DatumCount) { - /* Field is not skewed and we can just copy the datum */ - - AcpiExSetBufferDatum (ThisRawDatum, Buffer, BufferLength, - ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset); - BufferDatumOffset++; + break; } - 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 - */ - MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset); - - /* 2) Insert the second datum "above" the first datum */ - MergedDatum |= (ThisRawDatum << ObjDesc->CommonField.DatumValidBits); - - AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength, - ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset); - BufferDatumOffset++; - } + /* Write merged datum to target buffer */ - /* - * Save the raw datum that was just acquired since it may contain bits - * of the *next* field datum - */ - PreviousRawDatum = ThisRawDatum; - } + ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum, + ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, + BufferLength - BufferOffset)); - FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth; + BufferOffset += ObjDesc->CommonField.AccessByteWidth; + MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; } - /* For non-aligned case, there is one last datum to insert */ + /* Mask off any extra bits in the last datum */ - if (ObjDesc->CommonField.StartFieldBitOffset != 0) + BufferTailBits = ObjDesc->CommonField.BitLength % + ObjDesc->CommonField.AccessBitWidth; + if (BufferTailBits) { - MergedDatum = (ThisRawDatum >> ObjDesc->CommonField.StartFieldBitOffset); - - AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength, - ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset); + MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits); } + /* Write the last datum to the buffer */ + + ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum, + ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, + BufferLength - BufferOffset)); + return_ACPI_STATUS (AE_OK); } @@ -1109,180 +899,100 @@ AcpiExInsertIntoField ( UINT32 BufferLength) { ACPI_STATUS Status; - UINT32 FieldDatumByteOffset; - UINT32 DatumOffset; ACPI_INTEGER Mask; ACPI_INTEGER MergedDatum; - ACPI_INTEGER PreviousRawDatum; - ACPI_INTEGER ThisRawDatum; + ACPI_INTEGER RawDatum = 0; + UINT32 FieldOffset = 0; + UINT32 BufferOffset = 0; + UINT32 BufferTailBits; UINT32 DatumCount; + UINT32 FieldDatumCount; + UINT32 i; ACPI_FUNCTION_TRACE ("ExInsertIntoField"); - /* Validate buffer, compute number of datums */ + /* Validate input buffer */ - Status = AcpiExCommonBufferSetup (ObjDesc, BufferLength, &DatumCount); - if (ACPI_FAILURE (Status)) + if (BufferLength < ACPI_ROUND_BITS_UP_TO_BYTES ( + ObjDesc->CommonField.BitLength)) { - return_ACPI_STATUS (Status); - } - - /* - * Break the request into up to three parts (similar to an I/O request): - * 1) non-aligned part at start - * 2) aligned part in middle - * 3) non-aligned part at the end - */ - FieldDatumByteOffset = 0; - DatumOffset= 0; - - /* Get a single datum from the caller's buffer */ - - AcpiExGetBufferDatum (&PreviousRawDatum, Buffer, BufferLength, - ObjDesc->CommonField.AccessByteWidth, DatumOffset); - - /* - * Part1: - * Write a partial field datum if field does not begin on a datum boundary - * Note: The code in this section also handles the aligned case - * - * Construct Mask with 1 bits where the field is, 0 bits elsewhere - * (Only the bottom 5 bits of BitLength are valid for a shift operation) - * - * Mask off bits that are "below" the field (if any) - */ - Mask = ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset); - - /* If the field fits in one datum, may need to mask upper bits */ - - if ((ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM) && - ObjDesc->CommonField.EndFieldValidBits) - { - /* There are bits above the field, mask them off also */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Field size %X (bits) is too large for buffer (%X)\n", + ObjDesc->CommonField.BitLength, BufferLength)); - Mask &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits); + return_ACPI_STATUS (AE_BUFFER_OVERFLOW); } - /* Shift and mask the value into the field position */ - - MergedDatum = (PreviousRawDatum << ObjDesc->CommonField.StartFieldBitOffset); - MergedDatum &= Mask; + /* Compute the number of datums (access width data items) */ - /* Apply the update rule (if necessary) and write the datum to the field */ + Mask = ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset); + DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength, + ObjDesc->CommonField.AccessBitWidth); + FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength + + ObjDesc->CommonField.StartFieldBitOffset, + ObjDesc->CommonField.AccessBitWidth); - Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum, - FieldDatumByteOffset); - if (ACPI_FAILURE (Status)) - { - return_ACPI_STATUS (Status); - } + /* Get initial Datum from the input buffer */ - /* We just wrote the first datum */ + ACPI_MEMCPY (&RawDatum, Buffer, + ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, + BufferLength - BufferOffset)); - DatumOffset++; + MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset; - /* If the entire field fits within one datum, we are done. */ + /* Write the entire field */ - if ((DatumCount == 1) && - (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM)) + for (i = 1; i < FieldDatumCount; i++) { - return_ACPI_STATUS (AE_OK); - } + /* Write merged datum to the target field */ - /* - * Part2: - * Write the aligned data. - * - * We don't need to worry about the update rule for these data, because - * all of the bits in each datum are part of the field. - * - * The last datum must be special cased because it might contain bits - * that are not part of the field -- therefore the "update rule" must be - * applied in Part3 below. - */ - while (DatumOffset < DatumCount) - { - FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth; + MergedDatum &= Mask; + Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, + MergedDatum, FieldOffset); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } - /* - * Get the next raw buffer datum. It may contain bits of the previous - * field datum - */ - AcpiExGetBufferDatum (&ThisRawDatum, Buffer, BufferLength, - ObjDesc->CommonField.AccessByteWidth, DatumOffset); + /* Start new output datum by merging with previous input datum */ - /* Create the field datum based on the field alignment */ + FieldOffset += ObjDesc->CommonField.AccessByteWidth; + MergedDatum = RawDatum >> + (ObjDesc->CommonField.AccessBitWidth - + ObjDesc->CommonField.StartFieldBitOffset); + Mask = ACPI_INTEGER_MAX; - if (ObjDesc->CommonField.StartFieldBitOffset != 0) + if (i == DatumCount) { - /* - * Put together appropriate bits of the two raw buffer data to make - * a single complete field datum - */ - MergedDatum = - (PreviousRawDatum >> ObjDesc->CommonField.DatumValidBits) | - (ThisRawDatum << ObjDesc->CommonField.StartFieldBitOffset); - } - else - { - /* Field began aligned on datum boundary */ - - MergedDatum = ThisRawDatum; + break; } - /* - * Special handling for the last datum if the field does NOT end on - * a datum boundary. Update Rule must be applied to the bits outside - * the field. - */ - DatumOffset++; - if ((DatumOffset == DatumCount) && - (ObjDesc->CommonField.EndFieldValidBits)) - { - /* - * If there are dangling non-aligned bits, perform one more merged write - * Else - field is aligned at the end, no need for any more writes - */ + /* Get the next input datum from the buffer */ - /* - * Part3: - * This is the last datum and the field does not end on a datum boundary. - * Build the partial datum and write with the update rule. - * - * Mask off the unused bits above (after) the end-of-field - */ - Mask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits); - MergedDatum &= Mask; + BufferOffset += ObjDesc->CommonField.AccessByteWidth; + ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset, + ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, + BufferLength - BufferOffset)); + MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset; + } - /* Write the last datum with the update rule */ + /* Mask off any extra bits in the last datum */ - Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum, - FieldDatumByteOffset); - if (ACPI_FAILURE (Status)) - { - return_ACPI_STATUS (Status); - } - } - else - { - /* Normal (aligned) case -- write the completed datum */ + BufferTailBits = (ObjDesc->CommonField.BitLength + + ObjDesc->CommonField.StartFieldBitOffset) % + ObjDesc->CommonField.AccessBitWidth; + if (BufferTailBits) + { + Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits); + } - Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, - &MergedDatum, ACPI_WRITE); - if (ACPI_FAILURE (Status)) - { - return_ACPI_STATUS (Status); - } - } + /* Write the last datum to the field */ - /* - * Save the most recent datum since it may contain bits of the *next* - * field datum. Update current byte offset. - */ - PreviousRawDatum = ThisRawDatum; - } + MergedDatum &= Mask; + Status = AcpiExWriteWithUpdateRule (ObjDesc, + Mask, MergedDatum, FieldOffset); return_ACPI_STATUS (Status); } |
