This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / drivers / acpi / executer / exconvrt.c
index a29b865..04c04e4 100644 (file)
@@ -58,7 +58,7 @@
  * PARAMETERS:  obj_desc        - Object to be converted.  Must be an
  *                                Integer, Buffer, or String
  *              result_desc     - Where the new Integer object is returned
- *              Flags           - Used for string conversion
+ *              walk_state      - Current method state
  *
  * RETURN:      Status
  *
@@ -70,13 +70,13 @@ acpi_status
 acpi_ex_convert_to_integer (
        union acpi_operand_object       *obj_desc,
        union acpi_operand_object       **result_desc,
-       u32                             flags)
+       struct acpi_walk_state          *walk_state)
 {
-       union acpi_operand_object       *return_desc;
-       u8                              *pointer;
-       acpi_integer                    result;
        u32                             i;
+       union acpi_operand_object       *ret_desc;
        u32                             count;
+       u8                              *pointer;
+       acpi_integer                    result;
        acpi_status                     status;
 
 
@@ -85,17 +85,15 @@ acpi_ex_convert_to_integer (
 
        switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
        case ACPI_TYPE_INTEGER:
-
-               /* No conversion necessary */
-
                *result_desc = obj_desc;
                return_ACPI_STATUS (AE_OK);
 
-       case ACPI_TYPE_BUFFER:
        case ACPI_TYPE_STRING:
+               pointer = (u8 *) obj_desc->string.pointer;
+               count   = obj_desc->string.length;
+               break;
 
-               /* Note: Takes advantage of common buffer/string fields */
-
+       case ACPI_TYPE_BUFFER:
                pointer = obj_desc->buffer.pointer;
                count   = obj_desc->buffer.length;
                break;
@@ -128,12 +126,10 @@ acpi_ex_convert_to_integer (
        case ACPI_TYPE_STRING:
 
                /*
-                * Convert string to an integer - for most cases, the string must be
-                * hexadecimal as per the ACPI specification.  The only exception (as
-                * of ACPI 3.0) is that the to_integer() operator allows both decimal
-                * and hexadecimal strings (hex prefixed with "0x").
+                * Convert string to an integer
+                * String must be hexadecimal as per the ACPI specification
                 */
-               status = acpi_ut_strtoul64 ((char *) pointer, flags, &result);
+               status = acpi_ut_strtoul64 ((char *) pointer, 16, &result);
                if (ACPI_FAILURE (status)) {
                        return_ACPI_STATUS (status);
                }
@@ -143,8 +139,8 @@ acpi_ex_convert_to_integer (
        case ACPI_TYPE_BUFFER:
 
                /*
-                * Convert buffer to an integer - we simply grab enough raw data
-                * from the buffer to fill an integer
+                * Buffer conversion - we simply grab enough raw data from the
+                * buffer to fill an integer
                 */
                for (i = 0; i < count; i++) {
                        /*
@@ -165,15 +161,27 @@ acpi_ex_convert_to_integer (
        /*
         * Create a new integer
         */
-       return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
-       if (!return_desc) {
+       ret_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+       if (!ret_desc) {
                return_ACPI_STATUS (AE_NO_MEMORY);
        }
 
        /* Save the Result */
 
-       return_desc->integer.value = result;
-       *result_desc = return_desc;
+       ret_desc->integer.value = result;
+
+       /*
+        * If we are about to overwrite the original object on the operand stack,
+        * we must remove a reference on the original object because we are
+        * essentially removing it from the stack.
+        */
+       if (*result_desc == obj_desc) {
+               if (walk_state->opcode != AML_STORE_OP) {
+                       acpi_ut_remove_reference (obj_desc);
+               }
+       }
+
+       *result_desc = ret_desc;
        return_ACPI_STATUS (AE_OK);
 }
 
@@ -185,6 +193,7 @@ acpi_ex_convert_to_integer (
  * PARAMETERS:  obj_desc        - Object to be converted.  Must be an
  *                                Integer, Buffer, or String
  *              result_desc     - Where the new buffer object is returned
+ *              walk_state      - Current method state
  *
  * RETURN:      Status
  *
@@ -195,9 +204,11 @@ acpi_ex_convert_to_integer (
 acpi_status
 acpi_ex_convert_to_buffer (
        union acpi_operand_object       *obj_desc,
-       union acpi_operand_object       **result_desc)
+       union acpi_operand_object       **result_desc,
+       struct acpi_walk_state          *walk_state)
 {
-       union acpi_operand_object       *return_desc;
+       union acpi_operand_object       *ret_desc;
+       u32                             i;
        u8                              *new_buf;
 
 
@@ -219,17 +230,17 @@ acpi_ex_convert_to_buffer (
                 * Create a new Buffer object.
                 * Need enough space for one integer
                 */
-               return_desc = acpi_ut_create_buffer_object (acpi_gbl_integer_byte_width);
-               if (!return_desc) {
+               ret_desc = acpi_ut_create_buffer_object (acpi_gbl_integer_byte_width);
+               if (!ret_desc) {
                        return_ACPI_STATUS (AE_NO_MEMORY);
                }
 
-               /* Copy the integer to the buffer, LSB first */
+               /* Copy the integer to the buffer */
 
-               new_buf = return_desc->buffer.pointer;
-               ACPI_MEMCPY (new_buf,
-                                 &obj_desc->integer.value,
-                                 acpi_gbl_integer_byte_width);
+               new_buf = ret_desc->buffer.pointer;
+               for (i = 0; i < acpi_gbl_integer_byte_width; i++) {
+                       new_buf[i] = (u8) (obj_desc->integer.value >> (i * 8));
+               }
                break;
 
 
@@ -239,14 +250,14 @@ acpi_ex_convert_to_buffer (
                 * Create a new Buffer object
                 * Size will be the string length
                 */
-               return_desc = acpi_ut_create_buffer_object ((acpi_size) obj_desc->string.length);
-               if (!return_desc) {
+               ret_desc = acpi_ut_create_buffer_object ((acpi_size) obj_desc->string.length);
+               if (!ret_desc) {
                        return_ACPI_STATUS (AE_NO_MEMORY);
                }
 
                /* Copy the string to the buffer */
 
-               new_buf = return_desc->buffer.pointer;
+               new_buf = ret_desc->buffer.pointer;
                ACPI_STRNCPY ((char *) new_buf, (char *) obj_desc->string.pointer,
                        obj_desc->string.length);
                break;
@@ -258,20 +269,32 @@ acpi_ex_convert_to_buffer (
 
        /* Mark buffer initialized */
 
-       return_desc->common.flags |= AOPOBJ_DATA_VALID;
-       *result_desc = return_desc;
+       ret_desc->common.flags |= AOPOBJ_DATA_VALID;
+
+       /*
+        * If we are about to overwrite the original object on the operand stack,
+        * we must remove a reference on the original object because we are
+        * essentially removing it from the stack.
+        */
+       if (*result_desc == obj_desc) {
+               if (walk_state->opcode != AML_STORE_OP) {
+                       acpi_ut_remove_reference (obj_desc);
+               }
+       }
+
+       *result_desc = ret_desc;
        return_ACPI_STATUS (AE_OK);
 }
 
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ex_convert_to_ascii
+ * FUNCTION:    acpi_ex_convert_ascii
  *
  * PARAMETERS:  Integer         - Value to be converted
- *              Base            - ACPI_STRING_DECIMAL or ACPI_STRING_HEX
+ *              Base            - 10 or 16
  *              String          - Where the string is returned
- *              data_width      - Size of data item to be converted, in bytes
+ *              data_width      - Size of data item to be converted
  *
  * RETURN:      Actual string length
  *
@@ -282,81 +305,79 @@ acpi_ex_convert_to_buffer (
 u32
 acpi_ex_convert_to_ascii (
        acpi_integer                    integer,
-       u16                             base,
+       u32                             base,
        u8                              *string,
        u8                              data_width)
 {
+       u32                             i;
+       u32                             j;
+       u32                             k = 0;
+       char                            hex_digit;
        acpi_integer                    digit;
-       acpi_native_uint                i;
-       acpi_native_uint                j;
-       acpi_native_uint                k = 0;
-       acpi_native_uint                hex_length;
-       acpi_native_uint                decimal_length;
        u32                             remainder;
-       u8                              supress_zeros;
+       u32                             length;
+       u8                              leading_zero;
 
 
        ACPI_FUNCTION_ENTRY ();
 
 
+       if (data_width < sizeof (acpi_integer)) {
+               leading_zero = FALSE;
+               length = data_width;
+       }
+       else {
+               leading_zero = TRUE;
+               length = sizeof (acpi_integer);
+       }
+
        switch (base) {
        case 10:
 
-               /* Setup max length for the decimal number */
-
-               switch (data_width) {
-               case 1:
-                       decimal_length = ACPI_MAX8_DECIMAL_DIGITS;
-                       break;
-
-               case 4:
-                       decimal_length = ACPI_MAX32_DECIMAL_DIGITS;
-                       break;
-
-               case 8:
-               default:
-                       decimal_length = ACPI_MAX64_DECIMAL_DIGITS;
-                       break;
-               }
-
-               supress_zeros = TRUE;    /* No leading zeros */
                remainder = 0;
-
-               for (i = decimal_length; i > 0; i--) {
+               for (i = ACPI_MAX_DECIMAL_DIGITS; i > 0; i--) {
                        /* Divide by nth factor of 10 */
 
                        digit = integer;
                        for (j = 0; j < i; j++) {
-                               (void) acpi_ut_short_divide (digit, 10, &digit, &remainder);
+                               (void) acpi_ut_short_divide (&digit, 10, &digit, &remainder);
                        }
 
-                       /* Handle leading zeros */
+                       /* Create the decimal digit */
 
                        if (remainder != 0) {
-                               supress_zeros = FALSE;
+                               leading_zero = FALSE;
                        }
 
-                       if (!supress_zeros) {
+                       if (!leading_zero) {
                                string[k] = (u8) (ACPI_ASCII_ZERO + remainder);
                                k++;
                        }
                }
                break;
 
+
        case 16:
 
-               hex_length = ACPI_MUL_2 (data_width); /* 2 ascii hex chars per data byte */
+               /* Copy the integer to the buffer */
 
-               for (i = 0, j = (hex_length-1); i < hex_length; i++, j--) {
-                       /* Get one hex digit, most significant digits first */
+               for (i = 0, j = ((length * 2) -1); i < (length * 2); i++, j--) {
 
-                       string[k] = (u8) acpi_ut_hex_to_ascii_char (integer, ACPI_MUL_4 (j));
-                       k++;
+                       hex_digit = acpi_ut_hex_to_ascii_char (integer, (j * 4));
+                       if (hex_digit != ACPI_ASCII_ZERO) {
+                               leading_zero = FALSE;
+                       }
+
+                       if (!leading_zero) {
+                               string[k] = (u8) hex_digit;
+                               k++;
+                       }
                }
                break;
 
+
        default:
-               return (0);
+               break;
        }
 
        /*
@@ -371,7 +392,7 @@ acpi_ex_convert_to_ascii (
        }
 
        string [k] = 0;
-       return ((u32) k);
+       return (k);
 }
 
 
@@ -380,9 +401,11 @@ acpi_ex_convert_to_ascii (
  * FUNCTION:    acpi_ex_convert_to_string
  *
  * PARAMETERS:  obj_desc        - Object to be converted.  Must be an
- *                                Integer, Buffer, or String
+ *                                  Integer, Buffer, or String
  *              result_desc     - Where the string object is returned
- *              Type            - String flags (base and conversion type)
+ *              Base            - 10 or 16
+ *              max_length      - Max length of the returned string
+ *              walk_state      - Current method state
  *
  * RETURN:      Status
  *
@@ -394,14 +417,15 @@ acpi_status
 acpi_ex_convert_to_string (
        union acpi_operand_object       *obj_desc,
        union acpi_operand_object       **result_desc,
-       u32                             type)
+       u32                             base,
+       u32                             max_length,
+       struct acpi_walk_state          *walk_state)
 {
-       union acpi_operand_object       *return_desc;
+       union acpi_operand_object       *ret_desc;
        u8                              *new_buf;
-       u32                             string_length = 0;
-       u16                             base = 16;
+       u8                              *pointer;
+       u32                             string_length;
        u32                             i;
-       u8                              separator = ',';
 
 
        ACPI_FUNCTION_TRACE_PTR ("ex_convert_to_string", obj_desc);
@@ -410,129 +434,130 @@ acpi_ex_convert_to_string (
        switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
        case ACPI_TYPE_STRING:
 
-               /* No conversion necessary */
+               if (max_length >= obj_desc->string.length) {
+                       *result_desc = obj_desc;
+                       return_ACPI_STATUS (AE_OK);
+               }
+               else {
+                       /* Must copy the string first and then truncate it */
 
-               *result_desc = obj_desc;
-               return_ACPI_STATUS (AE_OK);
+                       return_ACPI_STATUS (AE_NOT_IMPLEMENTED);
+               }
 
 
        case ACPI_TYPE_INTEGER:
 
-               switch (type) {
-               case ACPI_EXPLICIT_CONVERT_DECIMAL:
-
-                       /* Make room for maximum decimal number */
-
+               string_length = acpi_gbl_integer_byte_width * 2;
+               if (base == 10) {
                        string_length = ACPI_MAX_DECIMAL_DIGITS;
-                       base = 10;
-                       break;
-
-               default:
-
-                       /* Two hex string characters for each integer byte */
-
-                       string_length = ACPI_MUL_2 (acpi_gbl_integer_byte_width);
-                       break;
                }
 
                /*
                 * Create a new String
-                * Need enough space for one ASCII integer (plus null terminator)
                 */
-               return_desc = acpi_ut_create_string_object ((acpi_size) string_length);
-               if (!return_desc) {
+               ret_desc = acpi_ut_create_internal_object (ACPI_TYPE_STRING);
+               if (!ret_desc) {
                        return_ACPI_STATUS (AE_NO_MEMORY);
                }
 
-               new_buf = return_desc->buffer.pointer;
+               /* Need enough space for one ASCII integer plus null terminator */
 
-               /* Convert integer to string */
+               new_buf = ACPI_MEM_CALLOCATE ((acpi_size) string_length + 1);
+               if (!new_buf) {
+                       ACPI_REPORT_ERROR
+                               (("ex_convert_to_string: Buffer allocation failure\n"));
+                       acpi_ut_remove_reference (ret_desc);
+                       return_ACPI_STATUS (AE_NO_MEMORY);
+               }
 
-               string_length = acpi_ex_convert_to_ascii (obj_desc->integer.value, base,
-                                  new_buf, acpi_gbl_integer_byte_width);
+               /* Convert */
+
+               i = acpi_ex_convert_to_ascii (obj_desc->integer.value, base, new_buf, sizeof (acpi_integer));
 
                /* Null terminate at the correct place */
 
-               return_desc->string.length = string_length;
-               new_buf [string_length] = 0;
+               if (max_length < i) {
+                       new_buf[max_length] = 0;
+                       ret_desc->string.length = max_length;
+               }
+               else {
+                       new_buf [i] = 0;
+                       ret_desc->string.length = i;
+               }
+
+               ret_desc->buffer.pointer = new_buf;
                break;
 
 
        case ACPI_TYPE_BUFFER:
 
-               switch (type) {
-               case ACPI_EXPLICIT_CONVERT_DECIMAL: /* Used by to_decimal_string operator */
-                       /*
-                        * From ACPI: "If Data is a buffer, it is converted to a string of
-                        * decimal values separated by commas."
-                        */
-                       base = 10;
-                       string_length = obj_desc->buffer.length; /* 4 chars for each decimal */
+               /* Find the string length */
 
-                       /*lint -fallthrough */
+               pointer = obj_desc->buffer.pointer;
+               for (string_length = 0; string_length < obj_desc->buffer.length; string_length++) {
+                       /* Exit on null terminator */
 
-               case ACPI_IMPLICIT_CONVERT_HEX:
-                       /*
-                        * From the ACPI spec:
-                        *"The entire contents of the buffer are converted to a string of
-                        * two-character hexadecimal numbers, each separated by a space."
-                        */
-                       if (type == ACPI_IMPLICIT_CONVERT_HEX) {
-                               separator = ' ';
+                       if (!pointer[string_length]) {
+                               break;
                        }
+               }
 
-                       /*lint -fallthrough */
-
-               case ACPI_EXPLICIT_CONVERT_HEX:     /* Used by to_hex_string operator */
-                       /*
-                        * From ACPI: "If Data is a buffer, it is converted to a string of
-                        * hexadecimal values separated by commas."
-                        */
-                       string_length += (obj_desc->buffer.length * 3);
-                       if (string_length > ACPI_MAX_STRING_CONVERSION) /* ACPI limit */ {
+               if (max_length > ACPI_MAX_STRING_CONVERSION) {
+                       if (string_length > ACPI_MAX_STRING_CONVERSION) {
                                return_ACPI_STATUS (AE_AML_STRING_LIMIT);
                        }
+               }
 
-                       /* Create a new string object and string buffer */
-
-                       return_desc = acpi_ut_create_string_object ((acpi_size) string_length -1);
-                       if (!return_desc) {
-                               return_ACPI_STATUS (AE_NO_MEMORY);
-                       }
+               /*
+                * Create a new string object
+                */
+               ret_desc = acpi_ut_create_internal_object (ACPI_TYPE_STRING);
+               if (!ret_desc) {
+                       return_ACPI_STATUS (AE_NO_MEMORY);
+               }
 
-                       new_buf = return_desc->buffer.pointer;
+               /* String length is the lesser of the Max or the actual length */
 
-                       /*
-                        * Convert buffer bytes to hex or decimal values
-                        * (separated by commas)
-                        */
-                       for (i = 0; i < obj_desc->buffer.length; i++) {
-                               new_buf += acpi_ex_convert_to_ascii (
-                                                (acpi_integer) obj_desc->buffer.pointer[i], base,
-                                                new_buf, 1);
-                               *new_buf++ = separator; /* each separated by a comma or space */
-                       }
+               if (max_length < string_length) {
+                       string_length = max_length;
+               }
 
-                       /* Null terminate the string (overwrites final comma from above) */
+               new_buf = ACPI_MEM_CALLOCATE ((acpi_size) string_length + 1);
+               if (!new_buf) {
+                       ACPI_REPORT_ERROR
+                               (("ex_convert_to_string: Buffer allocation failure\n"));
+                       acpi_ut_remove_reference (ret_desc);
+                       return_ACPI_STATUS (AE_NO_MEMORY);
+               }
 
-                       new_buf--;
-                       *new_buf = 0;
+               /* Copy the appropriate number of buffer characters */
 
-                       /* Recalculate length */
+               ACPI_MEMCPY (new_buf, pointer, string_length);
 
-                       return_desc->string.length = ACPI_STRLEN (return_desc->string.pointer);
-                       break;
+               /* Null terminate */
 
-               default:
-                       return_ACPI_STATUS (AE_BAD_PARAMETER);
-               }
+               new_buf [string_length] = 0;
+               ret_desc->buffer.pointer = new_buf;
+               ret_desc->string.length = string_length;
                break;
 
+
        default:
                return_ACPI_STATUS (AE_TYPE);
        }
 
-       *result_desc = return_desc;
+       /*
+        * If we are about to overwrite the original object on the operand stack,
+        * we must remove a reference on the original object because we are
+        * essentially removing it from the stack.
+        */
+       if (*result_desc == obj_desc) {
+               if (walk_state->opcode != AML_STORE_OP) {
+                       acpi_ut_remove_reference (obj_desc);
+               }
+       }
+
+       *result_desc = ret_desc;
        return_ACPI_STATUS (AE_OK);
 }
 
@@ -610,8 +635,7 @@ acpi_ex_convert_to_target_type (
                         * These types require an Integer operand.  We can convert
                         * a Buffer or a String to an Integer if necessary.
                         */
-                       status = acpi_ex_convert_to_integer (source_desc, result_desc,
-                                        16);
+                       status = acpi_ex_convert_to_integer (source_desc, result_desc, walk_state);
                        break;
 
 
@@ -621,8 +645,7 @@ acpi_ex_convert_to_target_type (
                         * The operand must be a String.  We can convert an
                         * Integer or Buffer if necessary
                         */
-                       status = acpi_ex_convert_to_string (source_desc, result_desc,
-                                        ACPI_IMPLICIT_CONVERT_HEX);
+                       status = acpi_ex_convert_to_string (source_desc, result_desc, 16, ACPI_UINT32_MAX, walk_state);
                        break;
 
 
@@ -632,7 +655,7 @@ acpi_ex_convert_to_target_type (
                         * The operand must be a Buffer.  We can convert an
                         * Integer or String if necessary
                         */
-                       status = acpi_ex_convert_to_buffer (source_desc, result_desc);
+                       status = acpi_ex_convert_to_buffer (source_desc, result_desc, walk_state);
                        break;