text: /******************************************************************************
   *
   * Module Name: nsrepair2 - Repair for objects returned by specific
   *                          predefined methods
   *
   *****************************************************************************/
  
  /*
   * Copyright (C) 2000 - 2017, Intel Corp.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions, and the following disclaimer,
   *    without modification.
   * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   *    substantially similar to the "NO WARRANTY" disclaimer below
   *    ("Disclaimer") and any redistribution must be conditioned upon
   *    including a substantially similar Disclaimer requirement for further
   *    binary redistribution.
   * 3. Neither the names of the above-listed copyright holders nor the names
   *    of any contributors may be used to endorse or promote products derived
   *    from this software without specific prior written permission.
   *
   * Alternatively, this software may be distributed under the terms of the
   * GNU General Public License ("GPL") version 2 as published by the Free
   * Software Foundation.
   *
   * NO WARRANTY
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
   * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   * POSSIBILITY OF SUCH DAMAGES.
   */
  
  #include <acpi/acpi.h>
  #include "accommon.h"
  #include "acnamesp.h"
  
  #define _COMPONENT          ACPI_NAMESPACE
  ACPI_MODULE_NAME("nsrepair2")
  
  /*
   * Information structure and handler for ACPI predefined names that can
   * be repaired on a per-name basis.
   */
  typedef
  acpi_status (*acpi_repair_function) (struct acpi_evaluate_info * info,
  				     union acpi_operand_object **
  				     return_object_ptr);
  
  typedef struct acpi_repair_info {
  	char name[ACPI_NAME_SIZE];
  	acpi_repair_function repair_function;
  
  } acpi_repair_info;
  
  /* Local prototypes */
  
  static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
  								   acpi_namespace_node
  								   *node);
  
  static acpi_status
  acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
  		   union acpi_operand_object **return_object_ptr);
  
  static acpi_status
  acpi_ns_repair_CID(struct acpi_evaluate_info *info,
  		   union acpi_operand_object **return_object_ptr);
  
  static acpi_status
  acpi_ns_repair_CST(struct acpi_evaluate_info *info,
  		   union acpi_operand_object **return_object_ptr);
  
  static acpi_status
  acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
  		   union acpi_operand_object **return_object_ptr);
  
  static acpi_status
  acpi_ns_repair_HID(struct acpi_evaluate_info *info,
  		   union acpi_operand_object **return_object_ptr);
  
  static acpi_status
  acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
  		   union acpi_operand_object **return_object_ptr);
  
  static acpi_status
  acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
  		   union acpi_operand_object **return_object_ptr);
  
  static acpi_status
  acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
  		   union acpi_operand_object **return_object_ptr);
  
  static acpi_status
  acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
  			  union acpi_operand_object *return_object,
  			  u32 start_index,
  			  u32 expected_count,
  			  u32 sort_index,
  			  u8 sort_direction, char *sort_key_name);
  
  /* Values for sort_direction above */
  
  #define ACPI_SORT_ASCENDING     0
  #define ACPI_SORT_DESCENDING    1
  
  static void
  acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index);
  
  static void
  acpi_ns_sort_list(union acpi_operand_object **elements,
  		  u32 count, u32 index, u8 sort_direction);
  
  /*
   * This table contains the names of the predefined methods for which we can
   * perform more complex repairs.
   *
   * As necessary:
   *
   * _ALR: Sort the list ascending by ambient_illuminance
   * _CID: Strings: uppercase all, remove any leading asterisk
   * _CST: Sort the list ascending by C state type
   * _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
   * _PRT: Fix reversed source_name and source_index
   * _PSS: Sort the list descending by Power
   * _TSS: Sort the list descending by Power
   *
   * Names that must be packages, but cannot be sorted:
   *
   * _BCL: Values are tied to the Package index where they appear, and cannot
   * be moved or sorted. These index values are used for _BQC and _BCM.
   * However, we can fix the case where a buffer is returned, by converting
   * it to a Package of integers.
   */
  static const struct acpi_repair_info acpi_ns_repairable_names[] = {
  	{"_ALR", acpi_ns_repair_ALR},
  	{"_CID", acpi_ns_repair_CID},
  	{"_CST", acpi_ns_repair_CST},
  	{"_FDE", acpi_ns_repair_FDE},
  	{"_GTM", acpi_ns_repair_FDE},	/* _GTM has same repair as _FDE */
  	{"_HID", acpi_ns_repair_HID},
  	{"_PRT", acpi_ns_repair_PRT},
  	{"_PSS", acpi_ns_repair_PSS},
  	{"_TSS", acpi_ns_repair_TSS},
  	{{0, 0, 0, 0}, NULL}	/* Table terminator */
  };
  
  #define ACPI_FDE_FIELD_COUNT        5
  #define ACPI_FDE_BYTE_BUFFER_SIZE   5
  #define ACPI_FDE_DWORD_BUFFER_SIZE  (ACPI_FDE_FIELD_COUNT * sizeof (u32))
  
  /******************************************************************************
   *
   * FUNCTION:    acpi_ns_complex_repairs
   *
   * PARAMETERS:  info                - Method execution information block
   *              node                - Namespace node for the method/object
   *              validate_status     - Original status of earlier validation
   *              return_object_ptr   - Pointer to the object returned from the
   *                                    evaluation of a method or object
   *
   * RETURN:      Status. AE_OK if repair was successful. If name is not
   *              matched, validate_status is returned.
   *
   * DESCRIPTION: Attempt to repair/convert a return object of a type that was
   *              not expected.
   *
   *****************************************************************************/
  
  acpi_status
  acpi_ns_complex_repairs(struct acpi_evaluate_info *info,
  			struct acpi_namespace_node *node,
  			acpi_status validate_status,
  			union acpi_operand_object **return_object_ptr)
  {
  	const struct acpi_repair_info *predefined;
  	acpi_status status;
  
  	/* Check if this name is in the list of repairable names */
  
  	predefined = acpi_ns_match_complex_repair(node);
  	if (!predefined) {
  		return (validate_status);
  	}
  
  	status = predefined->repair_function(info, return_object_ptr);
  	return (status);
  }
  
  /******************************************************************************
   *
   * FUNCTION:    acpi_ns_match_complex_repair
   *
   * PARAMETERS:  node                - Namespace node for the method/object
   *
   * RETURN:      Pointer to entry in repair table. NULL indicates not found.
   *
   * DESCRIPTION: Check an object name against the repairable object list.
   *
   *****************************************************************************/
  
  static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
  								   acpi_namespace_node
  								   *node)
  {
  	const struct acpi_repair_info *this_name;
  
  	/* Search info table for a repairable predefined method/object name */
  
  	this_name = acpi_ns_repairable_names;
  	while (this_name->repair_function) {
  		if (ACPI_COMPARE_NAME(node->name.ascii, this_name->name)) {
  			return (this_name);
  		}
  
  		this_name++;
  	}
  
  	return (NULL);		/* Not found */
  }
  
  /******************************************************************************
   *
   * FUNCTION:    acpi_ns_repair_ALR
   *
   * PARAMETERS:  info                - Method execution information block
   *              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 _ALR object. If necessary, sort the object list
   *              ascending by the ambient illuminance values.
   *
   *****************************************************************************/
  
  static acpi_status
  acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
  		   union acpi_operand_object **return_object_ptr)
  {
  	union acpi_operand_object *return_object = *return_object_ptr;
  	acpi_status status;
  
  	status = acpi_ns_check_sorted_list(info, return_object, 0, 2, 1,
  					   ACPI_SORT_ASCENDING,
  					   "AmbientIlluminance");
  
  	return (status);
  }
  
  /******************************************************************************
   *
   * FUNCTION:    acpi_ns_repair_FDE
   *
   * PARAMETERS:  info                - Method execution information block
   *              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 _FDE and _GTM objects. The expected return
   *              value is a Buffer of 5 DWORDs. This function repairs a common
   *              problem where the return value is a Buffer of BYTEs, not
   *              DWORDs.
   *
   *****************************************************************************/
  
  static acpi_status
  acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
  		   union acpi_operand_object **return_object_ptr)
  {
  	union acpi_operand_object *return_object = *return_object_ptr;
  	union acpi_operand_object *buffer_object;
  	u8 *byte_buffer;
  	u32 *dword_buffer;
  	u32 i;
  
  	ACPI_FUNCTION_NAME(ns_repair_FDE);
  
  	switch (return_object->common.type) {
  	case ACPI_TYPE_BUFFER:
  
  		/* This is the expected type. Length should be (at least) 5 DWORDs */
  
  		if (return_object->buffer.length >= ACPI_FDE_DWORD_BUFFER_SIZE) {
  			return (AE_OK);
  		}
  
  		/* We can only repair if we have exactly 5 BYTEs */
  
  		if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) {
  			ACPI_WARN_PREDEFINED((AE_INFO,
  					      info->full_pathname,
  					      info->node_flags,
  					      "Incorrect return buffer length %u, expected %u",
  					      return_object->buffer.length,
  					      ACPI_FDE_DWORD_BUFFER_SIZE));
  
  			return (AE_AML_OPERAND_TYPE);
  		}
  
  		/* Create the new (larger) buffer object */
  
  		buffer_object =
  		    acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE);
  		if (!buffer_object) {
  			return (AE_NO_MEMORY);
  		}
  
  		/* Expand each byte to a DWORD */
  
  		byte_buffer = return_object->buffer.pointer;
  		dword_buffer = ACPI_CAST_PTR(u32,
  					     buffer_object->buffer.pointer);
  
  		for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) {
  			*dword_buffer = (u32) *byte_buffer;
  			dword_buffer++;
  			byte_buffer++;
  		}
  
  		ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
  				  "%s Expanded Byte Buffer to expected DWord Buffer\n",
  				  info->full_pathname));
  		break;
  
  	default:
  
  		return (AE_AML_OPERAND_TYPE);
  	}
  
  	/* Delete the original return object, return the new buffer object */
  
  	acpi_ut_remove_reference(return_object);
  	*return_object_ptr = buffer_object;
  
  	info->return_flags |= ACPI_OBJECT_REPAIRED;
  	return (AE_OK);
  }
  
  /******************************************************************************
   *
   * FUNCTION:    acpi_ns_repair_CID
   *
   * PARAMETERS:  info                - Method execution information block
   *              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_evaluate_info *info,
  		   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(info, 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(info, element_ptr);
  		if (ACPI_FAILURE(status)) {
  			return (status);
  		}
  
  		if (original_element != *element_ptr) {
  
  			/* Update reference count of new object */
  
  			(*element_ptr)->common.reference_count =
  			    original_ref_count;
  		}
  
  		element_ptr++;
  	}
  
  	return (AE_OK);
  }
  
  /******************************************************************************
   *
   * FUNCTION:    acpi_ns_repair_CST
   *
   * PARAMETERS:  info                - Method execution information block
   *              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 _CST object:
   *              1. Sort the list ascending by C state type
   *              2. Ensure type cannot be zero
   *              3. A subpackage count of zero means _CST is meaningless
   *              4. Count must match the number of C state subpackages
   *
   *****************************************************************************/
  
  static acpi_status
  acpi_ns_repair_CST(struct acpi_evaluate_info *info,
  		   union acpi_operand_object **return_object_ptr)
  {
  	union acpi_operand_object *return_object = *return_object_ptr;
  	union acpi_operand_object **outer_elements;
  	u32 outer_element_count;
  	union acpi_operand_object *obj_desc;
  	acpi_status status;
  	u8 removing;
  	u32 i;
  
  	ACPI_FUNCTION_NAME(ns_repair_CST);
  
  	/*
  	 * Check if the C-state type values are proportional.
  	 */
  	outer_element_count = return_object->package.count - 1;
  	i = 0;
  	while (i < outer_element_count) {
  		outer_elements = &return_object->package.elements[i + 1];
  		removing = FALSE;
  
  		if ((*outer_elements)->package.count == 0) {
  			ACPI_WARN_PREDEFINED((AE_INFO,
  					      info->full_pathname,
  					      info->node_flags,
  					      "SubPackage[%u] - removing entry due to zero count",
  					      i));
  			removing = TRUE;
  			goto remove_element;
  		}
  
  		obj_desc = (*outer_elements)->package.elements[1];	/* Index1 = Type */
  		if ((u32)obj_desc->integer.value == 0) {
  			ACPI_WARN_PREDEFINED((AE_INFO,
  					      info->full_pathname,
  					      info->node_flags,
  					      "SubPackage[%u] - removing entry due to invalid Type(0)",
  					      i));
  			removing = TRUE;
  		}
  
  remove_element:
  		if (removing) {
  			acpi_ns_remove_element(return_object, i + 1);
  			outer_element_count--;
  		} else {
  			i++;
  		}
  	}
  
  	/* Update top-level package count, Type "Integer" checked elsewhere */
  
  	obj_desc = return_object->package.elements[0];
  	obj_desc->integer.value = outer_element_count;
  
  	/*
  	 * Entries (subpackages) in the _CST Package must be sorted by the
  	 * C-state type, in ascending order.
  	 */
  	status = acpi_ns_check_sorted_list(info, return_object, 1, 4, 1,
  					   ACPI_SORT_ASCENDING, "C-State Type");
  	if (ACPI_FAILURE(status)) {
  		return (status);
  	}
  
  	return (AE_OK);
  }
  
  /******************************************************************************
   *
   * FUNCTION:    acpi_ns_repair_HID
   *
   * PARAMETERS:  info                - Method execution information block
   *              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_evaluate_info *info,
  		   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,
  				      info->full_pathname, info->node_flags,
  				      "Invalid zero-length _HID or _CID string"));
  
  		/* Return AE_OK anyway, let driver handle it */
  
  		info->return_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",
  				  info->full_pathname));
  	}
  
  	/*
  	 * Copy and uppercase the string. From the ACPI 5.0 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
  	 * "NNNN####" where N is an uppercase letter or decimal digit, and
  	 * # is a hex digit.
  	 */
  	for (dest = new_string->string.pointer; *source; dest++, source++) {
  		*dest = (char)toupper((int)*source);
  	}
  
  	acpi_ut_remove_reference(return_object);
  	*return_object_ptr = new_string;
  	return (AE_OK);
  }
  
  /******************************************************************************
   *
   * FUNCTION:    acpi_ns_repair_PRT
   *
   * PARAMETERS:  info                - Method execution information block
   *              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 _PRT object. If necessary, fix reversed
   *              source_name and source_index field, a common BIOS bug.
   *
   *****************************************************************************/
  
  static acpi_status
  acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
  		   union acpi_operand_object **return_object_ptr)
  {
  	union acpi_operand_object *package_object = *return_object_ptr;
  	union acpi_operand_object **top_object_list;
  	union acpi_operand_object **sub_object_list;
  	union acpi_operand_object *obj_desc;
  	union acpi_operand_object *sub_package;
  	u32 element_count;
  	u32 index;
  
  	/* Each element in the _PRT package is a subpackage */
  
  	top_object_list = package_object->package.elements;
  	element_count = package_object->package.count;
  
  	/* Examine each subpackage */
  
  	for (index = 0; index < element_count; index++, top_object_list++) {
  		sub_package = *top_object_list;
  		sub_object_list = sub_package->package.elements;
  
  		/* Check for minimum required element count */
  
  		if (sub_package->package.count < 4) {
  			continue;
  		}
  
  		/*
  		 * If the BIOS has erroneously reversed the _PRT source_name (index 2)
  		 * and the source_index (index 3), fix it. _PRT is important enough to
  		 * workaround this BIOS error. This also provides compatibility with
  		 * other ACPI implementations.
  		 */
  		obj_desc = sub_object_list[3];
  		if (!obj_desc || (obj_desc->common.type != ACPI_TYPE_INTEGER)) {
  			sub_object_list[3] = sub_object_list[2];
  			sub_object_list[2] = obj_desc;
  			info->return_flags |= ACPI_OBJECT_REPAIRED;
  
  			ACPI_WARN_PREDEFINED((AE_INFO,
  					      info->full_pathname,
  					      info->node_flags,
  					      "PRT[%X]: Fixed reversed SourceName and SourceIndex",
  					      index));
  		}
  	}
  
  	return (AE_OK);
  }
  
  /******************************************************************************
   *
   * FUNCTION:    acpi_ns_repair_PSS
   *
   * PARAMETERS:  info                - Method execution information block
   *              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 _PSS object. If necessary, sort the object list
   *              by the CPU frequencies. Check that the power dissipation values
   *              are all proportional to CPU frequency (i.e., sorting by
   *              frequency should be the same as sorting by power.)
   *
   *****************************************************************************/
  
  static acpi_status
  acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
  		   union acpi_operand_object **return_object_ptr)
  {
  	union acpi_operand_object *return_object = *return_object_ptr;
  	union acpi_operand_object **outer_elements;
  	u32 outer_element_count;
  	union acpi_operand_object **elements;
  	union acpi_operand_object *obj_desc;
  	u32 previous_value;
  	acpi_status status;
  	u32 i;
  
  	/*
  	 * Entries (subpackages) in the _PSS Package must be sorted by power
  	 * dissipation, in descending order. If it appears that the list is
  	 * incorrectly sorted, sort it. We sort by cpu_frequency, since this
  	 * should be proportional to the power.
  	 */
  	status = acpi_ns_check_sorted_list(info, return_object, 0, 6, 0,
  					   ACPI_SORT_DESCENDING,
  					   "CpuFrequency");
  	if (ACPI_FAILURE(status)) {
  		return (status);
  	}
  
  	/*
  	 * We now know the list is correctly sorted by CPU frequency. Check if
  	 * the power dissipation values are proportional.
  	 */
  	previous_value = ACPI_UINT32_MAX;
  	outer_elements = return_object->package.elements;
  	outer_element_count = return_object->package.count;
  
  	for (i = 0; i < outer_element_count; i++) {
  		elements = (*outer_elements)->package.elements;
  		obj_desc = elements[1];	/* Index1 = power_dissipation */
  
  		if ((u32)obj_desc->integer.value > previous_value) {
  			ACPI_WARN_PREDEFINED((AE_INFO,
  					      info->full_pathname,
  					      info->node_flags,
  					      "SubPackage[%u,%u] - suspicious power dissipation values",
  					      i - 1, i));
  		}
  
  		previous_value = (u32) obj_desc->integer.value;
  		outer_elements++;
  	}
  
  	return (AE_OK);
  }
  
  /******************************************************************************
   *
   * FUNCTION:    acpi_ns_repair_TSS
   *
   * PARAMETERS:  info                - Method execution information block
   *              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 _TSS object. If necessary, sort the object list
   *              descending by the power dissipation values.
   *
   *****************************************************************************/
  
  static acpi_status
  acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
  		   union acpi_operand_object **return_object_ptr)
  {
  	union acpi_operand_object *return_object = *return_object_ptr;
  	acpi_status status;
  	struct acpi_namespace_node *node;
  
  	/*
  	 * We can only sort the _TSS return package if there is no _PSS in the
  	 * same scope. This is because if _PSS is present, the ACPI specification
  	 * dictates that the _TSS Power Dissipation field is to be ignored, and
  	 * therefore some BIOSs leave garbage values in the _TSS Power field(s).
  	 * In this case, it is best to just return the _TSS package as-is.
  	 * (May, 2011)
  	 */
  	status = acpi_ns_get_node(info->node, "^_PSS",
  				  ACPI_NS_NO_UPSEARCH, &node);
  	if (ACPI_SUCCESS(status)) {
  		return (AE_OK);
  	}
  
  	status = acpi_ns_check_sorted_list(info, return_object, 0, 5, 1,
  					   ACPI_SORT_DESCENDING,
  					   "PowerDissipation");
  
  	return (status);
  }
  
  /******************************************************************************
   *
   * FUNCTION:    acpi_ns_check_sorted_list
   *
   * PARAMETERS:  info                - Method execution information block
   *              return_object       - Pointer to the top-level returned object
   *              start_index         - Index of the first subpackage
   *              expected_count      - Minimum length of each subpackage
   *              sort_index          - Subpackage entry to sort on
   *              sort_direction      - Ascending or descending
   *              sort_key_name       - Name of the sort_index field
   *
   * RETURN:      Status. AE_OK if the list is valid and is sorted correctly or
   *              has been repaired by sorting the list.
   *
   * DESCRIPTION: Check if the package list is valid and sorted correctly by the
   *              sort_index. If not, then sort the list.
   *
   *****************************************************************************/
  
  static acpi_status
  acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
  			  union acpi_operand_object *return_object,
  			  u32 start_index,
  			  u32 expected_count,
  			  u32 sort_index,
  			  u8 sort_direction, char *sort_key_name)
  {
  	u32 outer_element_count;
  	union acpi_operand_object **outer_elements;
  	union acpi_operand_object **elements;
  	union acpi_operand_object *obj_desc;
  	u32 i;
  	u32 previous_value;
  
  	ACPI_FUNCTION_NAME(ns_check_sorted_list);
  
  	/* The top-level object must be a package */
  
  	if (return_object->common.type != ACPI_TYPE_PACKAGE) {
  		return (AE_AML_OPERAND_TYPE);
  	}
  
  	/*
  	 * NOTE: assumes list of subpackages contains no NULL elements.
  	 * Any NULL elements should have been removed by earlier call
  	 * to acpi_ns_remove_null_elements.
  	 */
  	outer_element_count = return_object->package.count;
  	if (!outer_element_count || start_index >= outer_element_count) {
  		return (AE_AML_PACKAGE_LIMIT);
  	}
  
  	outer_elements = &return_object->package.elements[start_index];
  	outer_element_count -= start_index;
  
  	previous_value = 0;
  	if (sort_direction == ACPI_SORT_DESCENDING) {
  		previous_value = ACPI_UINT32_MAX;
  	}
  
  	/* Examine each subpackage */
  
  	for (i = 0; i < outer_element_count; i++) {
  
  		/* Each element of the top-level package must also be a package */
  
  		if ((*outer_elements)->common.type != ACPI_TYPE_PACKAGE) {
  			return (AE_AML_OPERAND_TYPE);
  		}
  
  		/* Each subpackage must have the minimum length */
  
  		if ((*outer_elements)->package.count < expected_count) {
  			return (AE_AML_PACKAGE_LIMIT);
  		}
  
  		elements = (*outer_elements)->package.elements;
  		obj_desc = elements[sort_index];
  
  		if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
  			return (AE_AML_OPERAND_TYPE);
  		}
  
  		/*
  		 * The list must be sorted in the specified order. If we detect a
  		 * discrepancy, sort the entire list.
  		 */
  		if (((sort_direction == ACPI_SORT_ASCENDING) &&
  		     (obj_desc->integer.value < previous_value)) ||
  		    ((sort_direction == ACPI_SORT_DESCENDING) &&
  		     (obj_desc->integer.value > previous_value))) {
  			acpi_ns_sort_list(&return_object->package.
  					  elements[start_index],
  					  outer_element_count, sort_index,
  					  sort_direction);
  
  			info->return_flags |= ACPI_OBJECT_REPAIRED;
  
  			ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
  					  "%s: Repaired unsorted list - now sorted by %s\n",
  					  info->full_pathname, sort_key_name));
  			return (AE_OK);
  		}
  
  		previous_value = (u32) obj_desc->integer.value;
  		outer_elements++;
  	}
  
  	return (AE_OK);
  }
  
  /******************************************************************************
   *
   * FUNCTION:    acpi_ns_sort_list
   *
   * PARAMETERS:  elements            - Package object element list
   *              count               - Element count for above
   *              index               - Sort by which package element
   *              sort_direction      - Ascending or Descending sort
   *
   * RETURN:      None
   *
   * DESCRIPTION: Sort the objects that are in a package element list.
   *
   * NOTE: Assumes that all NULL elements have been removed from the package,
   *       and that all elements have been verified to be of type Integer.
   *
   *****************************************************************************/
  
  static void
  acpi_ns_sort_list(union acpi_operand_object **elements,
  		  u32 count, u32 index, u8 sort_direction)
  {
  	union acpi_operand_object *obj_desc1;
  	union acpi_operand_object *obj_desc2;
  	union acpi_operand_object *temp_obj;
  	u32 i;
  	u32 j;
  
  	/* Simple bubble sort */
  
  	for (i = 1; i < count; i++) {
  		for (j = (count - 1); j >= i; j--) {
  			obj_desc1 = elements[j - 1]->package.elements[index];
  			obj_desc2 = elements[j]->package.elements[index];
  
  			if (((sort_direction == ACPI_SORT_ASCENDING) &&
  			     (obj_desc1->integer.value >
  			      obj_desc2->integer.value))
  			    || ((sort_direction == ACPI_SORT_DESCENDING)
  				&& (obj_desc1->integer.value <
  				    obj_desc2->integer.value))) {
  				temp_obj = elements[j - 1];
  				elements[j - 1] = elements[j];
  				elements[j] = temp_obj;
  			}
  		}
  	}
  }
  
  /******************************************************************************
   *
   * FUNCTION:    acpi_ns_remove_element
   *
   * PARAMETERS:  obj_desc            - Package object element list
   *              index               - Index of element to remove
   *
   * RETURN:      None
   *
   * DESCRIPTION: Remove the requested element of a package and delete it.
   *
   *****************************************************************************/
  
  static void
  acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index)
  {
  	union acpi_operand_object **source;
  	union acpi_operand_object **dest;
  	u32 count;
  	u32 new_count;
  	u32 i;
  
  	ACPI_FUNCTION_NAME(ns_remove_element);
  
  	count = obj_desc->package.count;
  	new_count = count - 1;
  
  	source = obj_desc->package.elements;
  	dest = source;
  
  	/* Examine all elements of the package object, remove matched index */
  
  	for (i = 0; i < count; i++) {
  		if (i == index) {
  			acpi_ut_remove_reference(*source);	/* Remove one ref for being in pkg */
  			acpi_ut_remove_reference(*source);
  		} else {
  			*dest = *source;
  			dest++;
  		}
  
  		source++;
  	}
  
  	/* NULL terminate list and update the package count */
  
  	*dest = NULL;
  	obj_desc->package.count = new_count;
  }
  