vserver 1.9.5.x5
[linux-2.6.git] / drivers / acpi / executer / exfldio.c
index 03ccfb9..9d0f9d2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2004, R. Byron Moore
+ * Copyright (C) 2000 - 2005, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -139,7 +139,7 @@ acpi_ex_setup_region (
                        if (ACPI_ROUND_UP (rgn_desc->region.length,
                                           obj_desc->common_field.access_byte_width) >=
                                (obj_desc->common_field.base_byte_offset +
-                                obj_desc->common_field.access_byte_width +
+                                (acpi_native_uint) obj_desc->common_field.access_byte_width +
                                 field_datum_byte_offset)) {
                                return_ACPI_STATUS (AE_OK);
                        }
@@ -610,210 +610,6 @@ acpi_ex_write_with_update_rule (
 }
 
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ex_get_buffer_datum
- *
- * PARAMETERS:  Datum               - Where the Datum is returned
- *              Buffer              - Raw field buffer
- *              buffer_length       - Entire length (used for big-endian only)
- *              byte_granularity    - 1/2/4/8 Granularity of the field
- *                                    (aka Datum Size)
- *              buffer_offset       - Datum offset into the buffer
- *
- * RETURN:      none
- *
- * DESCRIPTION: Get a datum from the buffer according to the buffer field
- *              byte granularity
- *
- ******************************************************************************/
-
-void
-acpi_ex_get_buffer_datum (
-       acpi_integer                    *datum,
-       void                            *buffer,
-       u32                             buffer_length,
-       u32                             byte_granularity,
-       u32                             buffer_offset)
-{
-       u32                             index;
-
-
-       ACPI_FUNCTION_TRACE_U32 ("ex_get_buffer_datum", byte_granularity);
-
-
-       /* Get proper index into buffer (handles big/little endian) */
-
-       index = ACPI_BUFFER_INDEX (buffer_length, buffer_offset, byte_granularity);
-
-       /* Move the requested number of bytes */
-
-       switch (byte_granularity) {
-       case ACPI_FIELD_BYTE_GRANULARITY:
-
-               *datum = ((u8 *) buffer) [index];
-               break;
-
-       case ACPI_FIELD_WORD_GRANULARITY:
-
-               ACPI_MOVE_16_TO_64 (datum, &(((u16 *) buffer) [index]));
-               break;
-
-       case ACPI_FIELD_DWORD_GRANULARITY:
-
-               ACPI_MOVE_32_TO_64 (datum, &(((u32 *) buffer) [index]));
-               break;
-
-       case ACPI_FIELD_QWORD_GRANULARITY:
-
-               ACPI_MOVE_64_TO_64 (datum, &(((u64 *) buffer) [index]));
-               break;
-
-       default:
-               /* Should not get here */
-               break;
-       }
-
-       return_VOID;
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ex_set_buffer_datum
- *
- * PARAMETERS:  merged_datum        - Value to store
- *              Buffer              - Receiving buffer
- *              buffer_length       - Entire length (used for big-endian only)
- *              byte_granularity    - 1/2/4/8 Granularity of the field
- *                                    (aka Datum Size)
- *              buffer_offset       - Datum offset into the buffer
- *
- * RETURN:      none
- *
- * DESCRIPTION: Store the merged datum to the buffer according to the
- *              byte granularity
- *
- ******************************************************************************/
-
-void
-acpi_ex_set_buffer_datum (
-       acpi_integer                    merged_datum,
-       void                            *buffer,
-       u32                             buffer_length,
-       u32                             byte_granularity,
-       u32                             buffer_offset)
-{
-       u32                             index;
-
-
-       ACPI_FUNCTION_TRACE_U32 ("ex_set_buffer_datum", byte_granularity);
-
-
-       /* Get proper index into buffer (handles big/little endian) */
-
-       index = ACPI_BUFFER_INDEX (buffer_length, buffer_offset, byte_granularity);
-
-       /* Move the requested number of bytes */
-
-       switch (byte_granularity) {
-       case ACPI_FIELD_BYTE_GRANULARITY:
-
-               ((u8 *) buffer) [index] = (u8) merged_datum;
-               break;
-
-       case ACPI_FIELD_WORD_GRANULARITY:
-
-               ACPI_MOVE_64_TO_16 (&(((u16 *) buffer)[index]), &merged_datum);
-               break;
-
-       case ACPI_FIELD_DWORD_GRANULARITY:
-
-               ACPI_MOVE_64_TO_32 (&(((u32 *) buffer)[index]), &merged_datum);
-               break;
-
-       case ACPI_FIELD_QWORD_GRANULARITY:
-
-               ACPI_MOVE_64_TO_64 (&(((u64 *) buffer)[index]), &merged_datum);
-               break;
-
-       default:
-               /* Should not get here */
-               break;
-       }
-
-       return_VOID;
-}
-
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ex_common_buffer_setup
- *
- * PARAMETERS:  obj_desc            - Field object
- *              buffer_length       - Length of caller's buffer
- *              datum_count         - Where the datum_count is returned
- *
- * RETURN:      Status, datum_count
- *
- * 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
-acpi_ex_common_buffer_setup (
-       union acpi_operand_object       *obj_desc,
-       u32                             buffer_length,
-       u32                             *datum_count)
-{
-       u32                             byte_field_length;
-       u32                             actual_byte_field_length;
-
-
-       ACPI_FUNCTION_TRACE ("ex_common_buffer_setup");
-
-
-       /*
-        * 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.
-        */
-       byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (
-                        obj_desc->common_field.bit_length);
-       if (byte_field_length > buffer_length) {
-               ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
-                       "Field size %X (bytes) is too large for buffer (%X)\n",
-                       byte_field_length, buffer_length));
-
-               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)
-        */
-       actual_byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (
-                         obj_desc->common_field.start_field_bit_offset +
-                         obj_desc->common_field.bit_length);
-
-
-       *datum_count = ACPI_ROUND_UP_TO (actual_byte_field_length,
-                          obj_desc->common_field.access_byte_width);
-
-       ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
-               "buffer_bytes %X, actual_bytes %X, Datums %X, byte_gran %X\n",
-               byte_field_length, actual_byte_field_length,
-               *datum_count, obj_desc->common_field.access_byte_width));
-
-       return_ACPI_STATUS (AE_OK);
-}
-
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ex_extract_from_field
@@ -835,128 +631,92 @@ acpi_ex_extract_from_field (
        u32                             buffer_length)
 {
        acpi_status                     status;
-       u32                             field_datum_byte_offset;
-       u32                             buffer_datum_offset;
-       acpi_integer                    previous_raw_datum = 0;
-       acpi_integer                    this_raw_datum = 0;
-       acpi_integer                    merged_datum = 0;
+       acpi_integer                    raw_datum;
+       acpi_integer                    merged_datum;
+       u32                             field_offset = 0;
+       u32                             buffer_offset = 0;
+       u32                             buffer_tail_bits;
        u32                             datum_count;
+       u32                             field_datum_count;
        u32                             i;
 
 
        ACPI_FUNCTION_TRACE ("ex_extract_from_field");
 
 
-       /* Validate buffer, compute number of datums */
+       /* Validate target buffer and clear it */
 
-       status = acpi_ex_common_buffer_setup (obj_desc, buffer_length, &datum_count);
-       if (ACPI_FAILURE (status)) {
-               return_ACPI_STATUS (status);
-       }
+       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));
 
-       /*
-        * 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, buffer_length);
 
-       field_datum_byte_offset = 0;
-       buffer_datum_offset= 0;
-
-       /* Read the entire field */
-
-       for (i = 0; i < datum_count; i++) {
-               status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset,
-                                 &this_raw_datum, ACPI_READ);
-               if (ACPI_FAILURE (status)) {
-                       return_ACPI_STATUS (status);
-               }
-
-               /* We might actually be done if the request fits in one datum */
-
-               if ((datum_count == 1) &&
-                       (obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM)) {
-                       /* 1) Shift the valid data bits down to start at bit 0 */
+       /* Compute the number of datums (access width data items) */
 
-                       merged_datum = (this_raw_datum >> 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);
 
-                       /* 2) Mask off any upper unused bits (bits not part of the field) */
+       /* Priming read from the field */
 
-                       if (obj_desc->common_field.end_buffer_valid_bits) {
-                               merged_datum &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits);
-                       }
+       status = acpi_ex_field_datum_io (obj_desc, field_offset, &raw_datum, ACPI_READ);
+       if (ACPI_FAILURE (status)) {
+               return_ACPI_STATUS (status);
+       }
+       merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset;
 
-                       /* Store the datum to the caller buffer */
+       /* Read the rest of the field */
 
-                       acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length,
-                                       obj_desc->common_field.access_byte_width, buffer_datum_offset);
+       for (i = 1; i < field_datum_count; i++) {
+               /* Get next input datum from the field */
 
-                       return_ACPI_STATUS (AE_OK);
+               field_offset += obj_desc->common_field.access_byte_width;
+               status = acpi_ex_field_datum_io (obj_desc, field_offset,
+                                 &raw_datum, ACPI_READ);
+               if (ACPI_FAILURE (status)) {
+                       return_ACPI_STATUS (status);
                }
 
-               /* Special handling for the last datum to ignore extra bits */
-
-               if ((i >= (datum_count -1))          &&
-                       (obj_desc->common_field.end_field_valid_bits)) {
-                       /*
-                        * This is the last iteration of the loop.  We need to clear
-                        * any unused bits (bits that are not part of this field) before
-                        * we store the final merged datum into the caller buffer.
-                        */
-                       this_raw_datum &=
-                               ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits);
-               }
+               /* Merge with previous datum if necessary */
 
-               /*
-                * Create the (possibly) merged datum to be stored to the caller buffer
-                */
-               if (obj_desc->common_field.start_field_bit_offset == 0) {
-                       /* Field is not skewed and we can just copy the datum */
+               merged_datum |= raw_datum <<
+                       (obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset);
 
-                       acpi_ex_set_buffer_datum (this_raw_datum, buffer, buffer_length,
-                                       obj_desc->common_field.access_byte_width, buffer_datum_offset);
-                       buffer_datum_offset++;
+               if (i == datum_count) {
+                       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
-                                */
-                               merged_datum = (previous_raw_datum >> obj_desc->common_field.start_field_bit_offset);
+               /* Write merged datum to target buffer */
 
-                               /* 2) Insert the second datum "above" the first datum */
+               ACPI_MEMCPY (((char *) buffer) + buffer_offset, &merged_datum,
+                       ACPI_MIN(obj_desc->common_field.access_byte_width,
+                                        buffer_length - buffer_offset));
 
-                               merged_datum |= (this_raw_datum << obj_desc->common_field.datum_valid_bits);
-
-                               acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length,
-                                               obj_desc->common_field.access_byte_width, buffer_datum_offset);
-                               buffer_datum_offset++;
-                       }
+               buffer_offset += obj_desc->common_field.access_byte_width;
+               merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset;
+       }
 
-                       /*
-                        * Save the raw datum that was just acquired since it may contain bits
-                        * of the *next* field datum
-                        */
-                       previous_raw_datum = this_raw_datum;
-               }
+       /* Mask off any extra bits in the last datum */
 
-               field_datum_byte_offset += obj_desc->common_field.access_byte_width;
+       buffer_tail_bits = obj_desc->common_field.bit_length % obj_desc->common_field.access_bit_width;
+       if (buffer_tail_bits) {
+               merged_datum &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits);
        }
 
-       /* For non-aligned case, there is one last datum to insert */
+       /* Write the last datum to the buffer */
 
-       if (obj_desc->common_field.start_field_bit_offset != 0) {
-               merged_datum = (this_raw_datum >> obj_desc->common_field.start_field_bit_offset);
-
-               acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length,
-                               obj_desc->common_field.access_byte_width, buffer_datum_offset);
-       }
+       ACPI_MEMCPY (((char *) buffer) + buffer_offset, &merged_datum,
+               ACPI_MIN(obj_desc->common_field.access_byte_width,
+                                buffer_length - buffer_offset));
 
        return_ACPI_STATUS (AE_OK);
 }
@@ -983,169 +743,91 @@ acpi_ex_insert_into_field (
        u32                             buffer_length)
 {
        acpi_status                     status;
-       u32                             field_datum_byte_offset;
-       u32                             datum_offset;
        acpi_integer                    mask;
        acpi_integer                    merged_datum;
-       acpi_integer                    previous_raw_datum;
-       acpi_integer                    this_raw_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 buffer, compute number of datums */
-
-       status = acpi_ex_common_buffer_setup (obj_desc, buffer_length, &datum_count);
-       if (ACPI_FAILURE (status)) {
-               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
-        */
-       field_datum_byte_offset = 0;
-       datum_offset= 0;
-
-       /* Get a single datum from the caller's buffer */
-
-       acpi_ex_get_buffer_datum (&previous_raw_datum, buffer, buffer_length,
-                       obj_desc->common_field.access_byte_width, datum_offset);
-
-       /*
-        * 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 bit_length are valid for a shift operation)
-        *
-        * Mask off bits that are "below" the field (if any)
-        */
-       mask = ACPI_MASK_BITS_BELOW (obj_desc->common_field.start_field_bit_offset);
-
-       /* If the field fits in one datum, may need to mask upper bits */
+       /* Validate input buffer */
 
-       if ((obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM) &&
-                obj_desc->common_field.end_field_valid_bits) {
-               /* There are bits above the field, mask them off also */
+       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));
 
-               mask &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits);
+               return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
        }
 
-       /* Shift and mask the value into the field position */
-
-       merged_datum = (previous_raw_datum << obj_desc->common_field.start_field_bit_offset);
-       merged_datum &= mask;
-
-       /* Apply the update rule (if necessary) and write the datum to the field */
+       /* Compute the number of datums (access width data items) */
 
-       status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum,
-                          field_datum_byte_offset);
-       if (ACPI_FAILURE (status)) {
-               return_ACPI_STATUS (status);
-       }
+       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);
 
-       /* We just wrote the first datum */
+       /* Get initial Datum from the input buffer */
 
-       datum_offset++;
+       ACPI_MEMCPY (&raw_datum, buffer,
+               ACPI_MIN(obj_desc->common_field.access_byte_width,
+                                buffer_length - buffer_offset));
 
-       /* If the entire field fits within one datum, we are done. */
+       merged_datum = raw_datum << obj_desc->common_field.start_field_bit_offset;
 
-       if ((datum_count == 1) &&
-          (obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM)) {
-               return_ACPI_STATUS (AE_OK);
-       }
+       /* Write the entire 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 (datum_offset < datum_count) {
-               field_datum_byte_offset += obj_desc->common_field.access_byte_width;
+       for (i = 1; i < field_datum_count; i++) {
+               /* Write merged datum to the target field */
 
-               /*
-                * Get the next raw buffer datum.  It may contain bits of the previous
-                * field datum
-                */
-               acpi_ex_get_buffer_datum (&this_raw_datum, buffer, buffer_length,
-                               obj_desc->common_field.access_byte_width, datum_offset);
+               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);
+               }
 
-               /* Create the field datum based on the field alignment */
+               /* Start new output datum by merging with previous input datum */
 
-               if (obj_desc->common_field.start_field_bit_offset != 0) {
-                       /*
-                        * Put together appropriate bits of the two raw buffer data to make
-                        * a single complete field datum
-                        */
-                       merged_datum =
-                               (previous_raw_datum >> obj_desc->common_field.datum_valid_bits) |
-                               (this_raw_datum << obj_desc->common_field.start_field_bit_offset);
-               }
-               else {
-                       /* Field began aligned on datum boundary */
+               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;
 
-                       merged_datum = this_raw_datum;
+               if (i == datum_count) {
+                       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.
-                */
-               datum_offset++;
-               if ((datum_offset == datum_count) &&
-                       (obj_desc->common_field.end_field_valid_bits)) {
-                       /*
-                        * 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 (obj_desc->common_field.end_field_valid_bits);
-                       merged_datum &= mask;
+               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;
+       }
 
-                       /* Write the last datum with the update rule */
+       /* Mask off any extra bits in the last datum */
 
-                       status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum,
-                                          field_datum_byte_offset);
-                       if (ACPI_FAILURE (status)) {
-                               return_ACPI_STATUS (status);
-                       }
-               }
-               else {
-                       /* Normal (aligned) case -- write the completed 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);
+       }
 
-                       status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset,
-                                         &merged_datum, 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.
-                */
-               previous_raw_datum = this_raw_datum;
-       }
+       merged_datum &= mask;
+       status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_offset);
 
        return_ACPI_STATUS (status);
 }