Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 77b23f71 authored by Bob Moore's avatar Bob Moore Committed by Len Brown
Browse files

ACPICA: Add repair for _HID and _CID strings



This dynamic repair will fix these problems:
1) Remove a leading asterisk in the string
2) Uppercase the entire string

Signed-off-by: default avatarBob Moore <robert.moore@intel.com>
Signed-off-by: default avatarLin Ming <ming.m.lin@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent cc84e262
Loading
Loading
Loading
Loading
+163 −0
Original line number Diff line number Diff line
@@ -73,10 +73,18 @@ static acpi_status
acpi_ns_repair_ALR(struct acpi_predefined_data *data,
		   union acpi_operand_object **return_object_ptr);

static acpi_status
acpi_ns_repair_CID(struct acpi_predefined_data *data,
		   union acpi_operand_object **return_object_ptr);

static acpi_status
acpi_ns_repair_FDE(struct acpi_predefined_data *data,
		   union acpi_operand_object **return_object_ptr);

static acpi_status
acpi_ns_repair_HID(struct acpi_predefined_data *data,
		   union acpi_operand_object **return_object_ptr);

static acpi_status
acpi_ns_repair_PSS(struct acpi_predefined_data *data,
		   union acpi_operand_object **return_object_ptr);
@@ -108,8 +116,10 @@ acpi_ns_sort_list(union acpi_operand_object **elements,
 * As necessary:
 *
 * _ALR: Sort the list ascending by ambient_illuminance
 * _CID: Strings: uppercase all, remove any leading asterisk
 * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
 * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
 * _HID: Strings: uppercase all, remove any leading asterisk
 * _PSS: Sort the list descending by Power
 * _TSS: Sort the list descending by Power
 *
@@ -122,8 +132,10 @@ acpi_ns_sort_list(union acpi_operand_object **elements,
 */
static const struct acpi_repair_info acpi_ns_repairable_names[] = {
	{"_ALR", acpi_ns_repair_ALR},
	{"_CID", acpi_ns_repair_CID},
	{"_FDE", acpi_ns_repair_FDE},
	{"_GTM", acpi_ns_repair_FDE},	/* _GTM has same repair as _FDE */
	{"_HID", acpi_ns_repair_HID},
	{"_PSS", acpi_ns_repair_PSS},
	{"_TSS", acpi_ns_repair_TSS},
	{{0, 0, 0, 0}, NULL}	/* Table terminator */
@@ -319,6 +331,157 @@ acpi_ns_repair_FDE(struct acpi_predefined_data *data,
	return (AE_OK);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_repair_CID
 *
 * PARAMETERS:  Data                - Pointer to validation data structure
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 *
 * DESCRIPTION: Repair for the _CID object. If a string, ensure that all
 *              letters are uppercase and that there is no leading asterisk.
 *              If a Package, ensure same for all string elements.
 *
 *****************************************************************************/

static acpi_status
acpi_ns_repair_CID(struct acpi_predefined_data *data,
		   union acpi_operand_object **return_object_ptr)
{
	acpi_status status;
	union acpi_operand_object *return_object = *return_object_ptr;
	union acpi_operand_object **element_ptr;
	union acpi_operand_object *original_element;
	u16 original_ref_count;
	u32 i;

	/* Check for _CID as a simple string */

	if (return_object->common.type == ACPI_TYPE_STRING) {
		status = acpi_ns_repair_HID(data, return_object_ptr);
		return (status);
	}

	/* Exit if not a Package */

	if (return_object->common.type != ACPI_TYPE_PACKAGE) {
		return (AE_OK);
	}

	/* Examine each element of the _CID package */

	element_ptr = return_object->package.elements;
	for (i = 0; i < return_object->package.count; i++) {
		original_element = *element_ptr;
		original_ref_count = original_element->common.reference_count;

		status = acpi_ns_repair_HID(data, element_ptr);
		if (ACPI_FAILURE(status)) {
			return (status);
		}

		/* Take care with reference counts */

		if (original_element != *element_ptr) {

			/* Element was replaced */

			(*element_ptr)->common.reference_count =
			    original_ref_count;

			acpi_ut_remove_reference(original_element);
		}

		element_ptr++;
	}

	return (AE_OK);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_repair_HID
 *
 * PARAMETERS:  Data                - Pointer to validation data structure
 *              return_object_ptr   - Pointer to the object returned from the
 *                                    evaluation of a method or object
 *
 * RETURN:      Status. AE_OK if object is OK or was repaired successfully
 *
 * DESCRIPTION: Repair for the _HID object. If a string, ensure that all
 *              letters are uppercase and that there is no leading asterisk.
 *
 *****************************************************************************/

static acpi_status
acpi_ns_repair_HID(struct acpi_predefined_data *data,
		   union acpi_operand_object **return_object_ptr)
{
	union acpi_operand_object *return_object = *return_object_ptr;
	union acpi_operand_object *new_string;
	char *source;
	char *dest;

	ACPI_FUNCTION_NAME(ns_repair_HID);

	/* We only care about string _HID objects (not integers) */

	if (return_object->common.type != ACPI_TYPE_STRING) {
		return (AE_OK);
	}

	if (return_object->string.length == 0) {
		ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
				      "Invalid zero-length _HID or _CID string"));

		/* Return AE_OK anyway, let driver handle it */

		data->flags |= ACPI_OBJECT_REPAIRED;
		return (AE_OK);
	}

	/* It is simplest to always create a new string object */

	new_string = acpi_ut_create_string_object(return_object->string.length);
	if (!new_string) {
		return (AE_NO_MEMORY);
	}

	/*
	 * Remove a leading asterisk if present. For some unknown reason, there
	 * are many machines in the field that contains IDs like this.
	 *
	 * Examples: "*PNP0C03", "*ACPI0003"
	 */
	source = return_object->string.pointer;
	if (*source == '*') {
		source++;
		new_string->string.length--;

		ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
				  "%s: Removed invalid leading asterisk\n",
				  data->pathname));
	}

	/*
	 * Copy and uppercase the string. From the ACPI specification:
	 *
	 * A valid PNP ID must be of the form "AAA####" where A is an uppercase
	 * letter and # is a hex digit. A valid ACPI ID must be of the form
	 * "ACPI####" where # is a hex digit.
	 */
	for (dest = new_string->string.pointer; *source; dest++, source++) {
		*dest = (char)ACPI_TOUPPER(*source);
	}

	acpi_ut_remove_reference(return_object);
	*return_object_ptr = new_string;
	return (AE_OK);
}

/******************************************************************************
 *
 * FUNCTION:    acpi_ns_repair_TSS