162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: nsrepair - Repair for objects returned by predefined methods 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci *****************************************************************************/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <acpi/acpi.h> 1162306a36Sopenharmony_ci#include "accommon.h" 1262306a36Sopenharmony_ci#include "acnamesp.h" 1362306a36Sopenharmony_ci#include "acinterp.h" 1462306a36Sopenharmony_ci#include "acpredef.h" 1562306a36Sopenharmony_ci#include "amlresrc.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define _COMPONENT ACPI_NAMESPACE 1862306a36Sopenharmony_ciACPI_MODULE_NAME("nsrepair") 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/******************************************************************************* 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * This module attempts to repair or convert objects returned by the 2362306a36Sopenharmony_ci * predefined methods to an object type that is expected, as per the ACPI 2462306a36Sopenharmony_ci * specification. The need for this code is dictated by the many machines that 2562306a36Sopenharmony_ci * return incorrect types for the standard predefined methods. Performing these 2662306a36Sopenharmony_ci * conversions here, in one place, eliminates the need for individual ACPI 2762306a36Sopenharmony_ci * device drivers to do the same. Note: Most of these conversions are different 2862306a36Sopenharmony_ci * than the internal object conversion routines used for implicit object 2962306a36Sopenharmony_ci * conversion. 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * The following conversions can be performed as necessary: 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * Integer -> String 3462306a36Sopenharmony_ci * Integer -> Buffer 3562306a36Sopenharmony_ci * String -> Integer 3662306a36Sopenharmony_ci * String -> Buffer 3762306a36Sopenharmony_ci * Buffer -> Integer 3862306a36Sopenharmony_ci * Buffer -> String 3962306a36Sopenharmony_ci * Buffer -> Package of Integers 4062306a36Sopenharmony_ci * Package -> Package of one Package 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * Additional conversions that are available: 4362306a36Sopenharmony_ci * Convert a null return or zero return value to an end_tag descriptor 4462306a36Sopenharmony_ci * Convert an ASCII string to a Unicode buffer 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * An incorrect standalone object is wrapped with required outer package 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * Additional possible repairs: 4962306a36Sopenharmony_ci * Required package elements that are NULL replaced by Integer/String/Buffer 5062306a36Sopenharmony_ci * 5162306a36Sopenharmony_ci ******************************************************************************/ 5262306a36Sopenharmony_ci/* Local prototypes */ 5362306a36Sopenharmony_cistatic const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct 5462306a36Sopenharmony_ci acpi_namespace_node 5562306a36Sopenharmony_ci *node, 5662306a36Sopenharmony_ci u32 5762306a36Sopenharmony_ci return_btype, 5862306a36Sopenharmony_ci u32 5962306a36Sopenharmony_ci package_index); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * Special but simple repairs for some names. 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci * 2nd argument: Unexpected types that can be repaired 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_cistatic const struct acpi_simple_repair_info acpi_object_repair_info[] = { 6762306a36Sopenharmony_ci /* Resource descriptor conversions */ 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci {"_CRS", 7062306a36Sopenharmony_ci ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER | 7162306a36Sopenharmony_ci ACPI_RTYPE_NONE, 7262306a36Sopenharmony_ci ACPI_NOT_PACKAGE_ELEMENT, 7362306a36Sopenharmony_ci acpi_ns_convert_to_resource}, 7462306a36Sopenharmony_ci {"_DMA", 7562306a36Sopenharmony_ci ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER | 7662306a36Sopenharmony_ci ACPI_RTYPE_NONE, 7762306a36Sopenharmony_ci ACPI_NOT_PACKAGE_ELEMENT, 7862306a36Sopenharmony_ci acpi_ns_convert_to_resource}, 7962306a36Sopenharmony_ci {"_PRS", 8062306a36Sopenharmony_ci ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER | 8162306a36Sopenharmony_ci ACPI_RTYPE_NONE, 8262306a36Sopenharmony_ci ACPI_NOT_PACKAGE_ELEMENT, 8362306a36Sopenharmony_ci acpi_ns_convert_to_resource}, 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* Object reference conversions */ 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci {"_DEP", ACPI_RTYPE_STRING, ACPI_ALL_PACKAGE_ELEMENTS, 8862306a36Sopenharmony_ci acpi_ns_convert_to_reference}, 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci /* Unicode conversions */ 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci {"_MLS", ACPI_RTYPE_STRING, 1, 9362306a36Sopenharmony_ci acpi_ns_convert_to_unicode}, 9462306a36Sopenharmony_ci {"_STR", ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER, 9562306a36Sopenharmony_ci ACPI_NOT_PACKAGE_ELEMENT, 9662306a36Sopenharmony_ci acpi_ns_convert_to_unicode}, 9762306a36Sopenharmony_ci {{0, 0, 0, 0}, 0, 0, NULL} /* Table terminator */ 9862306a36Sopenharmony_ci}; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/******************************************************************************* 10162306a36Sopenharmony_ci * 10262306a36Sopenharmony_ci * FUNCTION: acpi_ns_simple_repair 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * PARAMETERS: info - Method execution information block 10562306a36Sopenharmony_ci * expected_btypes - Object types expected 10662306a36Sopenharmony_ci * package_index - Index of object within parent package (if 10762306a36Sopenharmony_ci * applicable - ACPI_NOT_PACKAGE_ELEMENT 10862306a36Sopenharmony_ci * otherwise) 10962306a36Sopenharmony_ci * return_object_ptr - Pointer to the object returned from the 11062306a36Sopenharmony_ci * evaluation of a method or object 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * RETURN: Status. AE_OK if repair was successful. 11362306a36Sopenharmony_ci * 11462306a36Sopenharmony_ci * DESCRIPTION: Attempt to repair/convert a return object of a type that was 11562306a36Sopenharmony_ci * not expected. 11662306a36Sopenharmony_ci * 11762306a36Sopenharmony_ci ******************************************************************************/ 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ciacpi_status 12062306a36Sopenharmony_ciacpi_ns_simple_repair(struct acpi_evaluate_info *info, 12162306a36Sopenharmony_ci u32 expected_btypes, 12262306a36Sopenharmony_ci u32 package_index, 12362306a36Sopenharmony_ci union acpi_operand_object **return_object_ptr) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci union acpi_operand_object *return_object = *return_object_ptr; 12662306a36Sopenharmony_ci union acpi_operand_object *new_object = NULL; 12762306a36Sopenharmony_ci acpi_status status; 12862306a36Sopenharmony_ci const struct acpi_simple_repair_info *predefined; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci ACPI_FUNCTION_NAME(ns_simple_repair); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* 13362306a36Sopenharmony_ci * Special repairs for certain names that are in the repair table. 13462306a36Sopenharmony_ci * Check if this name is in the list of repairable names. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_ci predefined = acpi_ns_match_simple_repair(info->node, 13762306a36Sopenharmony_ci info->return_btype, 13862306a36Sopenharmony_ci package_index); 13962306a36Sopenharmony_ci if (predefined) { 14062306a36Sopenharmony_ci if (!return_object) { 14162306a36Sopenharmony_ci ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, 14262306a36Sopenharmony_ci ACPI_WARN_ALWAYS, 14362306a36Sopenharmony_ci "Missing expected return value")); 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci status = predefined->object_converter(info->node, return_object, 14762306a36Sopenharmony_ci &new_object); 14862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* A fatal error occurred during a conversion */ 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, 15362306a36Sopenharmony_ci "During return object analysis")); 15462306a36Sopenharmony_ci return (status); 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci if (new_object) { 15762306a36Sopenharmony_ci goto object_repaired; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* 16262306a36Sopenharmony_ci * Do not perform simple object repair unless the return type is not 16362306a36Sopenharmony_ci * expected. 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_ci if (info->return_btype & expected_btypes) { 16662306a36Sopenharmony_ci return (AE_OK); 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci /* 17062306a36Sopenharmony_ci * At this point, we know that the type of the returned object was not 17162306a36Sopenharmony_ci * one of the expected types for this predefined name. Attempt to 17262306a36Sopenharmony_ci * repair the object by converting it to one of the expected object 17362306a36Sopenharmony_ci * types for this predefined name. 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* 17762306a36Sopenharmony_ci * If there is no return value, check if we require a return value for 17862306a36Sopenharmony_ci * this predefined name. Either one return value is expected, or none, 17962306a36Sopenharmony_ci * for both methods and other objects. 18062306a36Sopenharmony_ci * 18162306a36Sopenharmony_ci * Try to fix if there was no return object. Warning if failed to fix. 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_ci if (!return_object) { 18462306a36Sopenharmony_ci if (expected_btypes) { 18562306a36Sopenharmony_ci if (!(expected_btypes & ACPI_RTYPE_NONE) && 18662306a36Sopenharmony_ci package_index != ACPI_NOT_PACKAGE_ELEMENT) { 18762306a36Sopenharmony_ci ACPI_WARN_PREDEFINED((AE_INFO, 18862306a36Sopenharmony_ci info->full_pathname, 18962306a36Sopenharmony_ci ACPI_WARN_ALWAYS, 19062306a36Sopenharmony_ci "Found unexpected NULL package element")); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci status = 19362306a36Sopenharmony_ci acpi_ns_repair_null_element(info, 19462306a36Sopenharmony_ci expected_btypes, 19562306a36Sopenharmony_ci package_index, 19662306a36Sopenharmony_ci return_object_ptr); 19762306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 19862306a36Sopenharmony_ci return (AE_OK); /* Repair was successful */ 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (expected_btypes != ACPI_RTYPE_NONE) { 20362306a36Sopenharmony_ci ACPI_WARN_PREDEFINED((AE_INFO, 20462306a36Sopenharmony_ci info->full_pathname, 20562306a36Sopenharmony_ci ACPI_WARN_ALWAYS, 20662306a36Sopenharmony_ci "Missing expected return value")); 20762306a36Sopenharmony_ci return (AE_AML_NO_RETURN_VALUE); 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (expected_btypes & ACPI_RTYPE_INTEGER) { 21362306a36Sopenharmony_ci status = acpi_ns_convert_to_integer(return_object, &new_object); 21462306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 21562306a36Sopenharmony_ci goto object_repaired; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci if (expected_btypes & ACPI_RTYPE_STRING) { 21962306a36Sopenharmony_ci status = acpi_ns_convert_to_string(return_object, &new_object); 22062306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 22162306a36Sopenharmony_ci goto object_repaired; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci if (expected_btypes & ACPI_RTYPE_BUFFER) { 22562306a36Sopenharmony_ci status = acpi_ns_convert_to_buffer(return_object, &new_object); 22662306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 22762306a36Sopenharmony_ci goto object_repaired; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci if (expected_btypes & ACPI_RTYPE_PACKAGE) { 23162306a36Sopenharmony_ci /* 23262306a36Sopenharmony_ci * A package is expected. We will wrap the existing object with a 23362306a36Sopenharmony_ci * new package object. It is often the case that if a variable-length 23462306a36Sopenharmony_ci * package is required, but there is only a single object needed, the 23562306a36Sopenharmony_ci * BIOS will return that object instead of wrapping it with a Package 23662306a36Sopenharmony_ci * object. Note: after the wrapping, the package will be validated 23762306a36Sopenharmony_ci * for correct contents (expected object type or types). 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_ci status = 24062306a36Sopenharmony_ci acpi_ns_wrap_with_package(info, return_object, &new_object); 24162306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 24262306a36Sopenharmony_ci /* 24362306a36Sopenharmony_ci * The original object just had its reference count 24462306a36Sopenharmony_ci * incremented for being inserted into the new package. 24562306a36Sopenharmony_ci */ 24662306a36Sopenharmony_ci *return_object_ptr = new_object; /* New Package object */ 24762306a36Sopenharmony_ci info->return_flags |= ACPI_OBJECT_REPAIRED; 24862306a36Sopenharmony_ci return (AE_OK); 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci /* We cannot repair this object */ 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci return (AE_AML_OPERAND_TYPE); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ciobject_repaired: 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* Object was successfully repaired */ 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (package_index != ACPI_NOT_PACKAGE_ELEMENT) { 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci /* Update reference count of new object */ 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (!(info->return_flags & ACPI_OBJECT_WRAPPED)) { 26562306a36Sopenharmony_ci new_object->common.reference_count = 26662306a36Sopenharmony_ci return_object->common.reference_count; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, 27062306a36Sopenharmony_ci "%s: Converted %s to expected %s at Package index %u\n", 27162306a36Sopenharmony_ci info->full_pathname, 27262306a36Sopenharmony_ci acpi_ut_get_object_type_name(return_object), 27362306a36Sopenharmony_ci acpi_ut_get_object_type_name(new_object), 27462306a36Sopenharmony_ci package_index)); 27562306a36Sopenharmony_ci } else { 27662306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, 27762306a36Sopenharmony_ci "%s: Converted %s to expected %s\n", 27862306a36Sopenharmony_ci info->full_pathname, 27962306a36Sopenharmony_ci acpi_ut_get_object_type_name(return_object), 28062306a36Sopenharmony_ci acpi_ut_get_object_type_name(new_object))); 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* Delete old object, install the new return object */ 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci acpi_ut_remove_reference(return_object); 28662306a36Sopenharmony_ci *return_object_ptr = new_object; 28762306a36Sopenharmony_ci info->return_flags |= ACPI_OBJECT_REPAIRED; 28862306a36Sopenharmony_ci return (AE_OK); 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci/****************************************************************************** 29262306a36Sopenharmony_ci * 29362306a36Sopenharmony_ci * FUNCTION: acpi_ns_match_simple_repair 29462306a36Sopenharmony_ci * 29562306a36Sopenharmony_ci * PARAMETERS: node - Namespace node for the method/object 29662306a36Sopenharmony_ci * return_btype - Object type that was returned 29762306a36Sopenharmony_ci * package_index - Index of object within parent package (if 29862306a36Sopenharmony_ci * applicable - ACPI_NOT_PACKAGE_ELEMENT 29962306a36Sopenharmony_ci * otherwise) 30062306a36Sopenharmony_ci * 30162306a36Sopenharmony_ci * RETURN: Pointer to entry in repair table. NULL indicates not found. 30262306a36Sopenharmony_ci * 30362306a36Sopenharmony_ci * DESCRIPTION: Check an object name against the repairable object list. 30462306a36Sopenharmony_ci * 30562306a36Sopenharmony_ci *****************************************************************************/ 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct 30862306a36Sopenharmony_ci acpi_namespace_node 30962306a36Sopenharmony_ci *node, 31062306a36Sopenharmony_ci u32 31162306a36Sopenharmony_ci return_btype, 31262306a36Sopenharmony_ci u32 31362306a36Sopenharmony_ci package_index) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci const struct acpi_simple_repair_info *this_name; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* Search info table for a repairable predefined method/object name */ 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci this_name = acpi_object_repair_info; 32062306a36Sopenharmony_ci while (this_name->object_converter) { 32162306a36Sopenharmony_ci if (ACPI_COMPARE_NAMESEG(node->name.ascii, this_name->name)) { 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* Check if we can actually repair this name/type combination */ 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if ((return_btype & this_name->unexpected_btypes) && 32662306a36Sopenharmony_ci (this_name->package_index == 32762306a36Sopenharmony_ci ACPI_ALL_PACKAGE_ELEMENTS 32862306a36Sopenharmony_ci || package_index == this_name->package_index)) { 32962306a36Sopenharmony_ci return (this_name); 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci return (NULL); 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci this_name++; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return (NULL); /* Name was not found in the repair table */ 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci/******************************************************************************* 34262306a36Sopenharmony_ci * 34362306a36Sopenharmony_ci * FUNCTION: acpi_ns_repair_null_element 34462306a36Sopenharmony_ci * 34562306a36Sopenharmony_ci * PARAMETERS: info - Method execution information block 34662306a36Sopenharmony_ci * expected_btypes - Object types expected 34762306a36Sopenharmony_ci * package_index - Index of object within parent package (if 34862306a36Sopenharmony_ci * applicable - ACPI_NOT_PACKAGE_ELEMENT 34962306a36Sopenharmony_ci * otherwise) 35062306a36Sopenharmony_ci * return_object_ptr - Pointer to the object returned from the 35162306a36Sopenharmony_ci * evaluation of a method or object 35262306a36Sopenharmony_ci * 35362306a36Sopenharmony_ci * RETURN: Status. AE_OK if repair was successful. 35462306a36Sopenharmony_ci * 35562306a36Sopenharmony_ci * DESCRIPTION: Attempt to repair a NULL element of a returned Package object. 35662306a36Sopenharmony_ci * 35762306a36Sopenharmony_ci ******************************************************************************/ 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ciacpi_status 36062306a36Sopenharmony_ciacpi_ns_repair_null_element(struct acpi_evaluate_info *info, 36162306a36Sopenharmony_ci u32 expected_btypes, 36262306a36Sopenharmony_ci u32 package_index, 36362306a36Sopenharmony_ci union acpi_operand_object **return_object_ptr) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci union acpi_operand_object *return_object = *return_object_ptr; 36662306a36Sopenharmony_ci union acpi_operand_object *new_object; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci ACPI_FUNCTION_NAME(ns_repair_null_element); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* No repair needed if return object is non-NULL */ 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (return_object) { 37362306a36Sopenharmony_ci return (AE_OK); 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* 37762306a36Sopenharmony_ci * Attempt to repair a NULL element of a Package object. This applies to 37862306a36Sopenharmony_ci * predefined names that return a fixed-length package and each element 37962306a36Sopenharmony_ci * is required. It does not apply to variable-length packages where NULL 38062306a36Sopenharmony_ci * elements are allowed, especially at the end of the package. 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ci if (expected_btypes & ACPI_RTYPE_INTEGER) { 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* Need an integer - create a zero-value integer */ 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci new_object = acpi_ut_create_integer_object((u64)0); 38762306a36Sopenharmony_ci } else if (expected_btypes & ACPI_RTYPE_STRING) { 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* Need a string - create a NULL string */ 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci new_object = acpi_ut_create_string_object(0); 39262306a36Sopenharmony_ci } else if (expected_btypes & ACPI_RTYPE_BUFFER) { 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* Need a buffer - create a zero-length buffer */ 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci new_object = acpi_ut_create_buffer_object(0); 39762306a36Sopenharmony_ci } else { 39862306a36Sopenharmony_ci /* Error for all other expected types */ 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci return (AE_AML_OPERAND_TYPE); 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (!new_object) { 40462306a36Sopenharmony_ci return (AE_NO_MEMORY); 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* Set the reference count according to the parent Package object */ 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci new_object->common.reference_count = 41062306a36Sopenharmony_ci info->parent_package->common.reference_count; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, 41362306a36Sopenharmony_ci "%s: Converted NULL package element to expected %s at index %u\n", 41462306a36Sopenharmony_ci info->full_pathname, 41562306a36Sopenharmony_ci acpi_ut_get_object_type_name(new_object), 41662306a36Sopenharmony_ci package_index)); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci *return_object_ptr = new_object; 41962306a36Sopenharmony_ci info->return_flags |= ACPI_OBJECT_REPAIRED; 42062306a36Sopenharmony_ci return (AE_OK); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci/****************************************************************************** 42462306a36Sopenharmony_ci * 42562306a36Sopenharmony_ci * FUNCTION: acpi_ns_remove_null_elements 42662306a36Sopenharmony_ci * 42762306a36Sopenharmony_ci * PARAMETERS: info - Method execution information block 42862306a36Sopenharmony_ci * package_type - An acpi_return_package_types value 42962306a36Sopenharmony_ci * obj_desc - A Package object 43062306a36Sopenharmony_ci * 43162306a36Sopenharmony_ci * RETURN: None. 43262306a36Sopenharmony_ci * 43362306a36Sopenharmony_ci * DESCRIPTION: Remove all NULL package elements from packages that contain 43462306a36Sopenharmony_ci * a variable number of subpackages. For these types of 43562306a36Sopenharmony_ci * packages, NULL elements can be safely removed. 43662306a36Sopenharmony_ci * 43762306a36Sopenharmony_ci *****************************************************************************/ 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_civoid 44062306a36Sopenharmony_ciacpi_ns_remove_null_elements(struct acpi_evaluate_info *info, 44162306a36Sopenharmony_ci u8 package_type, 44262306a36Sopenharmony_ci union acpi_operand_object *obj_desc) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci union acpi_operand_object **source; 44562306a36Sopenharmony_ci union acpi_operand_object **dest; 44662306a36Sopenharmony_ci u32 count; 44762306a36Sopenharmony_ci u32 new_count; 44862306a36Sopenharmony_ci u32 i; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci ACPI_FUNCTION_NAME(ns_remove_null_elements); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* 45362306a36Sopenharmony_ci * We can safely remove all NULL elements from these package types: 45462306a36Sopenharmony_ci * PTYPE1_VAR packages contain a variable number of simple data types. 45562306a36Sopenharmony_ci * PTYPE2 packages contain a variable number of subpackages. 45662306a36Sopenharmony_ci */ 45762306a36Sopenharmony_ci switch (package_type) { 45862306a36Sopenharmony_ci case ACPI_PTYPE1_VAR: 45962306a36Sopenharmony_ci case ACPI_PTYPE2: 46062306a36Sopenharmony_ci case ACPI_PTYPE2_COUNT: 46162306a36Sopenharmony_ci case ACPI_PTYPE2_PKG_COUNT: 46262306a36Sopenharmony_ci case ACPI_PTYPE2_FIXED: 46362306a36Sopenharmony_ci case ACPI_PTYPE2_MIN: 46462306a36Sopenharmony_ci case ACPI_PTYPE2_REV_FIXED: 46562306a36Sopenharmony_ci case ACPI_PTYPE2_FIX_VAR: 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci default: 46962306a36Sopenharmony_ci case ACPI_PTYPE2_VAR_VAR: 47062306a36Sopenharmony_ci case ACPI_PTYPE1_FIXED: 47162306a36Sopenharmony_ci case ACPI_PTYPE1_OPTION: 47262306a36Sopenharmony_ci return; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci count = obj_desc->package.count; 47662306a36Sopenharmony_ci new_count = count; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci source = obj_desc->package.elements; 47962306a36Sopenharmony_ci dest = source; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci /* Examine all elements of the package object, remove nulls */ 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci for (i = 0; i < count; i++) { 48462306a36Sopenharmony_ci if (!*source) { 48562306a36Sopenharmony_ci new_count--; 48662306a36Sopenharmony_ci } else { 48762306a36Sopenharmony_ci *dest = *source; 48862306a36Sopenharmony_ci dest++; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci source++; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* Update parent package if any null elements were removed */ 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci if (new_count < count) { 49762306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, 49862306a36Sopenharmony_ci "%s: Found and removed %u NULL elements\n", 49962306a36Sopenharmony_ci info->full_pathname, (count - new_count))); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci /* NULL terminate list and update the package count */ 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci *dest = NULL; 50462306a36Sopenharmony_ci obj_desc->package.count = new_count; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci/******************************************************************************* 50962306a36Sopenharmony_ci * 51062306a36Sopenharmony_ci * FUNCTION: acpi_ns_wrap_with_package 51162306a36Sopenharmony_ci * 51262306a36Sopenharmony_ci * PARAMETERS: info - Method execution information block 51362306a36Sopenharmony_ci * original_object - Pointer to the object to repair. 51462306a36Sopenharmony_ci * obj_desc_ptr - The new package object is returned here 51562306a36Sopenharmony_ci * 51662306a36Sopenharmony_ci * RETURN: Status, new object in *obj_desc_ptr 51762306a36Sopenharmony_ci * 51862306a36Sopenharmony_ci * DESCRIPTION: Repair a common problem with objects that are defined to 51962306a36Sopenharmony_ci * return a variable-length Package of sub-objects. If there is 52062306a36Sopenharmony_ci * only one sub-object, some BIOS code mistakenly simply declares 52162306a36Sopenharmony_ci * the single object instead of a Package with one sub-object. 52262306a36Sopenharmony_ci * This function attempts to repair this error by wrapping a 52362306a36Sopenharmony_ci * Package object around the original object, creating the 52462306a36Sopenharmony_ci * correct and expected Package with one sub-object. 52562306a36Sopenharmony_ci * 52662306a36Sopenharmony_ci * Names that can be repaired in this manner include: 52762306a36Sopenharmony_ci * _ALR, _CSD, _HPX, _MLS, _PLD, _PRT, _PSS, _TRT, _TSS, 52862306a36Sopenharmony_ci * _BCL, _DOD, _FIX, _Sx 52962306a36Sopenharmony_ci * 53062306a36Sopenharmony_ci ******************************************************************************/ 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ciacpi_status 53362306a36Sopenharmony_ciacpi_ns_wrap_with_package(struct acpi_evaluate_info *info, 53462306a36Sopenharmony_ci union acpi_operand_object *original_object, 53562306a36Sopenharmony_ci union acpi_operand_object **obj_desc_ptr) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci union acpi_operand_object *pkg_obj_desc; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci ACPI_FUNCTION_NAME(ns_wrap_with_package); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* 54262306a36Sopenharmony_ci * Create the new outer package and populate it. The new 54362306a36Sopenharmony_ci * package will have a single element, the lone sub-object. 54462306a36Sopenharmony_ci */ 54562306a36Sopenharmony_ci pkg_obj_desc = acpi_ut_create_package_object(1); 54662306a36Sopenharmony_ci if (!pkg_obj_desc) { 54762306a36Sopenharmony_ci return (AE_NO_MEMORY); 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci pkg_obj_desc->package.elements[0] = original_object; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, 55362306a36Sopenharmony_ci "%s: Wrapped %s with expected Package object\n", 55462306a36Sopenharmony_ci info->full_pathname, 55562306a36Sopenharmony_ci acpi_ut_get_object_type_name(original_object))); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /* Return the new object in the object pointer */ 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci *obj_desc_ptr = pkg_obj_desc; 56062306a36Sopenharmony_ci info->return_flags |= ACPI_OBJECT_REPAIRED | ACPI_OBJECT_WRAPPED; 56162306a36Sopenharmony_ci return (AE_OK); 56262306a36Sopenharmony_ci} 563