summaryrefslogtreecommitdiffstats
path: root/drivers/acpi/acpica/nsconvert.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/acpica/nsconvert.c')
-rw-r--r--drivers/acpi/acpica/nsconvert.c490
1 files changed, 490 insertions, 0 deletions
diff --git a/drivers/acpi/acpica/nsconvert.c b/drivers/acpi/acpica/nsconvert.c
new file mode 100644
index 000000000..b02555fe3
--- /dev/null
+++ b/drivers/acpi/acpica/nsconvert.c
@@ -0,0 +1,490 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/******************************************************************************
+ *
+ * Module Name: nsconvert - Object conversions for objects returned by
+ * predefined methods
+ *
+ * Copyright (C) 2000 - 2022, Intel Corp.
+ *
+ *****************************************************************************/
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acinterp.h"
+#include "acpredef.h"
+#include "amlresrc.h"
+
+#define _COMPONENT ACPI_NAMESPACE
+ACPI_MODULE_NAME("nsconvert")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_convert_to_integer
+ *
+ * PARAMETERS: original_object - Object to be converted
+ * return_object - Where the new converted object is returned
+ *
+ * RETURN: Status. AE_OK if conversion was successful.
+ *
+ * DESCRIPTION: Attempt to convert a String/Buffer object to an Integer.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_ns_convert_to_integer(union acpi_operand_object *original_object,
+ union acpi_operand_object **return_object)
+{
+ union acpi_operand_object *new_object;
+ acpi_status status;
+ u64 value = 0;
+ u32 i;
+
+ switch (original_object->common.type) {
+ case ACPI_TYPE_STRING:
+
+ /* String-to-Integer conversion */
+
+ status =
+ acpi_ut_strtoul64(original_object->string.pointer, &value);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ break;
+
+ case ACPI_TYPE_BUFFER:
+
+ /* Buffer-to-Integer conversion. Max buffer size is 64 bits. */
+
+ if (original_object->buffer.length > 8) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ /* Extract each buffer byte to create the integer */
+
+ for (i = 0; i < original_object->buffer.length; i++) {
+ value |= ((u64)
+ original_object->buffer.pointer[i] << (i *
+ 8));
+ }
+ break;
+
+ default:
+
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ new_object = acpi_ut_create_integer_object(value);
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
+
+ *return_object = new_object;
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_convert_to_string
+ *
+ * PARAMETERS: original_object - Object to be converted
+ * return_object - Where the new converted object is returned
+ *
+ * RETURN: Status. AE_OK if conversion was successful.
+ *
+ * DESCRIPTION: Attempt to convert a Integer/Buffer object to a String.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_convert_to_string(union acpi_operand_object *original_object,
+ union acpi_operand_object **return_object)
+{
+ union acpi_operand_object *new_object;
+ acpi_size length;
+ acpi_status status;
+
+ switch (original_object->common.type) {
+ case ACPI_TYPE_INTEGER:
+ /*
+ * Integer-to-String conversion. Commonly, convert
+ * an integer of value 0 to a NULL string. The last element of
+ * _BIF and _BIX packages occasionally need this fix.
+ */
+ if (original_object->integer.value == 0) {
+
+ /* Allocate a new NULL string object */
+
+ new_object = acpi_ut_create_string_object(0);
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
+ } else {
+ status = acpi_ex_convert_to_string(original_object,
+ &new_object,
+ ACPI_IMPLICIT_CONVERT_HEX);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
+ break;
+
+ case ACPI_TYPE_BUFFER:
+ /*
+ * Buffer-to-String conversion. Use a to_string
+ * conversion, no transform performed on the buffer data. The best
+ * example of this is the _BIF method, where the string data from
+ * the battery is often (incorrectly) returned as buffer object(s).
+ */
+ length = 0;
+ while ((length < original_object->buffer.length) &&
+ (original_object->buffer.pointer[length])) {
+ length++;
+ }
+
+ /* Allocate a new string object */
+
+ new_object = acpi_ut_create_string_object(length);
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
+
+ /*
+ * Copy the raw buffer data with no transform. String is already NULL
+ * terminated at Length+1.
+ */
+ memcpy(new_object->string.pointer,
+ original_object->buffer.pointer, length);
+ break;
+
+ default:
+
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ *return_object = new_object;
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_convert_to_buffer
+ *
+ * PARAMETERS: original_object - Object to be converted
+ * return_object - Where the new converted object is returned
+ *
+ * RETURN: Status. AE_OK if conversion was successful.
+ *
+ * DESCRIPTION: Attempt to convert a Integer/String/Package object to a Buffer.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_convert_to_buffer(union acpi_operand_object *original_object,
+ union acpi_operand_object **return_object)
+{
+ union acpi_operand_object *new_object;
+ acpi_status status;
+ union acpi_operand_object **elements;
+ u32 *dword_buffer;
+ u32 count;
+ u32 i;
+
+ switch (original_object->common.type) {
+ case ACPI_TYPE_INTEGER:
+ /*
+ * Integer-to-Buffer conversion.
+ * Convert the Integer to a packed-byte buffer. _MAT and other
+ * objects need this sometimes, if a read has been performed on a
+ * Field object that is less than or equal to the global integer
+ * size (32 or 64 bits).
+ */
+ status =
+ acpi_ex_convert_to_buffer(original_object, &new_object);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ break;
+
+ case ACPI_TYPE_STRING:
+
+ /* String-to-Buffer conversion. Simple data copy */
+
+ new_object = acpi_ut_create_buffer_object
+ (original_object->string.length);
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
+
+ memcpy(new_object->buffer.pointer,
+ original_object->string.pointer,
+ original_object->string.length);
+ break;
+
+ case ACPI_TYPE_PACKAGE:
+ /*
+ * This case is often seen for predefined names that must return a
+ * Buffer object with multiple DWORD integers within. For example,
+ * _FDE and _GTM. The Package can be converted to a Buffer.
+ */
+
+ /* All elements of the Package must be integers */
+
+ elements = original_object->package.elements;
+ count = original_object->package.count;
+
+ for (i = 0; i < count; i++) {
+ if ((!*elements) ||
+ ((*elements)->common.type != ACPI_TYPE_INTEGER)) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+ elements++;
+ }
+
+ /* Create the new buffer object to replace the Package */
+
+ new_object = acpi_ut_create_buffer_object(ACPI_MUL_4(count));
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Copy the package elements (integers) to the buffer as DWORDs */
+
+ elements = original_object->package.elements;
+ dword_buffer = ACPI_CAST_PTR(u32, new_object->buffer.pointer);
+
+ for (i = 0; i < count; i++) {
+ *dword_buffer = (u32)(*elements)->integer.value;
+ dword_buffer++;
+ elements++;
+ }
+ break;
+
+ default:
+
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ *return_object = new_object;
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_convert_to_unicode
+ *
+ * PARAMETERS: scope - Namespace node for the method/object
+ * original_object - ASCII String Object to be converted
+ * return_object - Where the new converted object is returned
+ *
+ * RETURN: Status. AE_OK if conversion was successful.
+ *
+ * DESCRIPTION: Attempt to convert a String object to a Unicode string Buffer.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_convert_to_unicode(struct acpi_namespace_node *scope,
+ union acpi_operand_object *original_object,
+ union acpi_operand_object **return_object)
+{
+ union acpi_operand_object *new_object;
+ char *ascii_string;
+ u16 *unicode_buffer;
+ u32 unicode_length;
+ u32 i;
+
+ if (!original_object) {
+ return (AE_OK);
+ }
+
+ /* If a Buffer was returned, it must be at least two bytes long */
+
+ if (original_object->common.type == ACPI_TYPE_BUFFER) {
+ if (original_object->buffer.length < 2) {
+ return (AE_AML_OPERAND_VALUE);
+ }
+
+ *return_object = NULL;
+ return (AE_OK);
+ }
+
+ /*
+ * The original object is an ASCII string. Convert this string to
+ * a unicode buffer.
+ */
+ ascii_string = original_object->string.pointer;
+ unicode_length = (original_object->string.length * 2) + 2;
+
+ /* Create a new buffer object for the Unicode data */
+
+ new_object = acpi_ut_create_buffer_object(unicode_length);
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
+
+ unicode_buffer = ACPI_CAST_PTR(u16, new_object->buffer.pointer);
+
+ /* Convert ASCII to Unicode */
+
+ for (i = 0; i < original_object->string.length; i++) {
+ unicode_buffer[i] = (u16)ascii_string[i];
+ }
+
+ *return_object = new_object;
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_convert_to_resource
+ *
+ * PARAMETERS: scope - Namespace node for the method/object
+ * original_object - Object to be converted
+ * return_object - Where the new converted object is returned
+ *
+ * RETURN: Status. AE_OK if conversion was successful
+ *
+ * DESCRIPTION: Attempt to convert a Integer object to a resource_template
+ * Buffer.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_convert_to_resource(struct acpi_namespace_node *scope,
+ union acpi_operand_object *original_object,
+ union acpi_operand_object **return_object)
+{
+ union acpi_operand_object *new_object;
+ u8 *buffer;
+
+ /*
+ * We can fix the following cases for an expected resource template:
+ * 1. No return value (interpreter slack mode is disabled)
+ * 2. A "Return (Zero)" statement
+ * 3. A "Return empty buffer" statement
+ *
+ * We will return a buffer containing a single end_tag
+ * resource descriptor.
+ */
+ if (original_object) {
+ switch (original_object->common.type) {
+ case ACPI_TYPE_INTEGER:
+
+ /* We can only repair an Integer==0 */
+
+ if (original_object->integer.value) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+ break;
+
+ case ACPI_TYPE_BUFFER:
+
+ if (original_object->buffer.length) {
+
+ /* Additional checks can be added in the future */
+
+ *return_object = NULL;
+ return (AE_OK);
+ }
+ break;
+
+ case ACPI_TYPE_STRING:
+ default:
+
+ return (AE_AML_OPERAND_TYPE);
+ }
+ }
+
+ /* Create the new buffer object for the resource descriptor */
+
+ new_object = acpi_ut_create_buffer_object(2);
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
+
+ buffer = ACPI_CAST_PTR(u8, new_object->buffer.pointer);
+
+ /* Initialize the Buffer with a single end_tag descriptor */
+
+ buffer[0] = (ACPI_RESOURCE_NAME_END_TAG | ASL_RDESC_END_TAG_SIZE);
+ buffer[1] = 0x00;
+
+ *return_object = new_object;
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_convert_to_reference
+ *
+ * PARAMETERS: scope - Namespace node for the method/object
+ * original_object - Object to be converted
+ * return_object - Where the new converted object is returned
+ *
+ * RETURN: Status. AE_OK if conversion was successful
+ *
+ * DESCRIPTION: Attempt to convert a Integer object to a object_reference.
+ * Buffer.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_convert_to_reference(struct acpi_namespace_node *scope,
+ union acpi_operand_object *original_object,
+ union acpi_operand_object **return_object)
+{
+ union acpi_operand_object *new_object = NULL;
+ acpi_status status;
+ struct acpi_namespace_node *node;
+ union acpi_generic_state scope_info;
+ char *name;
+
+ ACPI_FUNCTION_NAME(ns_convert_to_reference);
+
+ /* Convert path into internal presentation */
+
+ status =
+ acpi_ns_internalize_name(original_object->string.pointer, &name);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Find the namespace node */
+
+ scope_info.scope.node =
+ ACPI_CAST_PTR(struct acpi_namespace_node, scope);
+ status =
+ acpi_ns_lookup(&scope_info, name, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
+ NULL, &node);
+ if (ACPI_FAILURE(status)) {
+
+ /* Check if we are resolving a named reference within a package */
+
+ ACPI_ERROR_NAMESPACE(&scope_info,
+ original_object->string.pointer, status);
+ goto error_exit;
+ }
+
+ /* Create and init a new internal ACPI object */
+
+ new_object = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE);
+ if (!new_object) {
+ status = AE_NO_MEMORY;
+ goto error_exit;
+ }
+ new_object->reference.node = node;
+ new_object->reference.object = node->object;
+ new_object->reference.class = ACPI_REFCLASS_NAME;
+
+ /*
+ * Increase reference of the object if needed (the object is likely a
+ * null for device nodes).
+ */
+ acpi_ut_add_reference(node->object);
+
+error_exit:
+ ACPI_FREE(name);
+ *return_object = new_object;
+ return (status);
+}