xref: /OK3568_Linux_fs/kernel/drivers/acpi/acpica/nsrepair.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2*4882a593Smuzhiyun /******************************************************************************
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Module Name: nsrepair - Repair for objects returned by predefined methods
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (C) 2000 - 2020, Intel Corp.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *****************************************************************************/
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <acpi/acpi.h>
11*4882a593Smuzhiyun #include "accommon.h"
12*4882a593Smuzhiyun #include "acnamesp.h"
13*4882a593Smuzhiyun #include "acinterp.h"
14*4882a593Smuzhiyun #include "acpredef.h"
15*4882a593Smuzhiyun #include "amlresrc.h"
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #define _COMPONENT          ACPI_NAMESPACE
18*4882a593Smuzhiyun ACPI_MODULE_NAME("nsrepair")
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /*******************************************************************************
21*4882a593Smuzhiyun  *
22*4882a593Smuzhiyun  * This module attempts to repair or convert objects returned by the
23*4882a593Smuzhiyun  * predefined methods to an object type that is expected, as per the ACPI
24*4882a593Smuzhiyun  * specification. The need for this code is dictated by the many machines that
25*4882a593Smuzhiyun  * return incorrect types for the standard predefined methods. Performing these
26*4882a593Smuzhiyun  * conversions here, in one place, eliminates the need for individual ACPI
27*4882a593Smuzhiyun  * device drivers to do the same. Note: Most of these conversions are different
28*4882a593Smuzhiyun  * than the internal object conversion routines used for implicit object
29*4882a593Smuzhiyun  * conversion.
30*4882a593Smuzhiyun  *
31*4882a593Smuzhiyun  * The following conversions can be performed as necessary:
32*4882a593Smuzhiyun  *
33*4882a593Smuzhiyun  * Integer -> String
34*4882a593Smuzhiyun  * Integer -> Buffer
35*4882a593Smuzhiyun  * String  -> Integer
36*4882a593Smuzhiyun  * String  -> Buffer
37*4882a593Smuzhiyun  * Buffer  -> Integer
38*4882a593Smuzhiyun  * Buffer  -> String
39*4882a593Smuzhiyun  * Buffer  -> Package of Integers
40*4882a593Smuzhiyun  * Package -> Package of one Package
41*4882a593Smuzhiyun  *
42*4882a593Smuzhiyun  * Additional conversions that are available:
43*4882a593Smuzhiyun  *  Convert a null return or zero return value to an end_tag descriptor
44*4882a593Smuzhiyun  *  Convert an ASCII string to a Unicode buffer
45*4882a593Smuzhiyun  *
46*4882a593Smuzhiyun  * An incorrect standalone object is wrapped with required outer package
47*4882a593Smuzhiyun  *
48*4882a593Smuzhiyun  * Additional possible repairs:
49*4882a593Smuzhiyun  * Required package elements that are NULL replaced by Integer/String/Buffer
50*4882a593Smuzhiyun  *
51*4882a593Smuzhiyun  ******************************************************************************/
52*4882a593Smuzhiyun /* Local prototypes */
53*4882a593Smuzhiyun static const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct
54*4882a593Smuzhiyun 									 acpi_namespace_node
55*4882a593Smuzhiyun 									 *node,
56*4882a593Smuzhiyun 									 u32
57*4882a593Smuzhiyun 									 return_btype,
58*4882a593Smuzhiyun 									 u32
59*4882a593Smuzhiyun 									 package_index);
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun /*
62*4882a593Smuzhiyun  * Special but simple repairs for some names.
63*4882a593Smuzhiyun  *
64*4882a593Smuzhiyun  * 2nd argument: Unexpected types that can be repaired
65*4882a593Smuzhiyun  */
66*4882a593Smuzhiyun static const struct acpi_simple_repair_info acpi_object_repair_info[] = {
67*4882a593Smuzhiyun 	/* Resource descriptor conversions */
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	{"_CRS",
70*4882a593Smuzhiyun 	 ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER |
71*4882a593Smuzhiyun 	 ACPI_RTYPE_NONE,
72*4882a593Smuzhiyun 	 ACPI_NOT_PACKAGE_ELEMENT,
73*4882a593Smuzhiyun 	 acpi_ns_convert_to_resource},
74*4882a593Smuzhiyun 	{"_DMA",
75*4882a593Smuzhiyun 	 ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER |
76*4882a593Smuzhiyun 	 ACPI_RTYPE_NONE,
77*4882a593Smuzhiyun 	 ACPI_NOT_PACKAGE_ELEMENT,
78*4882a593Smuzhiyun 	 acpi_ns_convert_to_resource},
79*4882a593Smuzhiyun 	{"_PRS",
80*4882a593Smuzhiyun 	 ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER |
81*4882a593Smuzhiyun 	 ACPI_RTYPE_NONE,
82*4882a593Smuzhiyun 	 ACPI_NOT_PACKAGE_ELEMENT,
83*4882a593Smuzhiyun 	 acpi_ns_convert_to_resource},
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	/* Object reference conversions */
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	{"_DEP", ACPI_RTYPE_STRING, ACPI_ALL_PACKAGE_ELEMENTS,
88*4882a593Smuzhiyun 	 acpi_ns_convert_to_reference},
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	/* Unicode conversions */
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	{"_MLS", ACPI_RTYPE_STRING, 1,
93*4882a593Smuzhiyun 	 acpi_ns_convert_to_unicode},
94*4882a593Smuzhiyun 	{"_STR", ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER,
95*4882a593Smuzhiyun 	 ACPI_NOT_PACKAGE_ELEMENT,
96*4882a593Smuzhiyun 	 acpi_ns_convert_to_unicode},
97*4882a593Smuzhiyun 	{{0, 0, 0, 0}, 0, 0, NULL}	/* Table terminator */
98*4882a593Smuzhiyun };
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun /*******************************************************************************
101*4882a593Smuzhiyun  *
102*4882a593Smuzhiyun  * FUNCTION:    acpi_ns_simple_repair
103*4882a593Smuzhiyun  *
104*4882a593Smuzhiyun  * PARAMETERS:  info                - Method execution information block
105*4882a593Smuzhiyun  *              expected_btypes     - Object types expected
106*4882a593Smuzhiyun  *              package_index       - Index of object within parent package (if
107*4882a593Smuzhiyun  *                                    applicable - ACPI_NOT_PACKAGE_ELEMENT
108*4882a593Smuzhiyun  *                                    otherwise)
109*4882a593Smuzhiyun  *              return_object_ptr   - Pointer to the object returned from the
110*4882a593Smuzhiyun  *                                    evaluation of a method or object
111*4882a593Smuzhiyun  *
112*4882a593Smuzhiyun  * RETURN:      Status. AE_OK if repair was successful.
113*4882a593Smuzhiyun  *
114*4882a593Smuzhiyun  * DESCRIPTION: Attempt to repair/convert a return object of a type that was
115*4882a593Smuzhiyun  *              not expected.
116*4882a593Smuzhiyun  *
117*4882a593Smuzhiyun  ******************************************************************************/
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun acpi_status
acpi_ns_simple_repair(struct acpi_evaluate_info * info,u32 expected_btypes,u32 package_index,union acpi_operand_object ** return_object_ptr)120*4882a593Smuzhiyun acpi_ns_simple_repair(struct acpi_evaluate_info *info,
121*4882a593Smuzhiyun 		      u32 expected_btypes,
122*4882a593Smuzhiyun 		      u32 package_index,
123*4882a593Smuzhiyun 		      union acpi_operand_object **return_object_ptr)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	union acpi_operand_object *return_object = *return_object_ptr;
126*4882a593Smuzhiyun 	union acpi_operand_object *new_object = NULL;
127*4882a593Smuzhiyun 	acpi_status status;
128*4882a593Smuzhiyun 	const struct acpi_simple_repair_info *predefined;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	ACPI_FUNCTION_NAME(ns_simple_repair);
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	/*
133*4882a593Smuzhiyun 	 * Special repairs for certain names that are in the repair table.
134*4882a593Smuzhiyun 	 * Check if this name is in the list of repairable names.
135*4882a593Smuzhiyun 	 */
136*4882a593Smuzhiyun 	predefined = acpi_ns_match_simple_repair(info->node,
137*4882a593Smuzhiyun 						 info->return_btype,
138*4882a593Smuzhiyun 						 package_index);
139*4882a593Smuzhiyun 	if (predefined) {
140*4882a593Smuzhiyun 		if (!return_object) {
141*4882a593Smuzhiyun 			ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
142*4882a593Smuzhiyun 					      ACPI_WARN_ALWAYS,
143*4882a593Smuzhiyun 					      "Missing expected return value"));
144*4882a593Smuzhiyun 		}
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 		status = predefined->object_converter(info->node, return_object,
147*4882a593Smuzhiyun 						      &new_object);
148*4882a593Smuzhiyun 		if (ACPI_FAILURE(status)) {
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 			/* A fatal error occurred during a conversion */
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 			ACPI_EXCEPTION((AE_INFO, status,
153*4882a593Smuzhiyun 					"During return object analysis"));
154*4882a593Smuzhiyun 			return (status);
155*4882a593Smuzhiyun 		}
156*4882a593Smuzhiyun 		if (new_object) {
157*4882a593Smuzhiyun 			goto object_repaired;
158*4882a593Smuzhiyun 		}
159*4882a593Smuzhiyun 	}
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	/*
162*4882a593Smuzhiyun 	 * Do not perform simple object repair unless the return type is not
163*4882a593Smuzhiyun 	 * expected.
164*4882a593Smuzhiyun 	 */
165*4882a593Smuzhiyun 	if (info->return_btype & expected_btypes) {
166*4882a593Smuzhiyun 		return (AE_OK);
167*4882a593Smuzhiyun 	}
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	/*
170*4882a593Smuzhiyun 	 * At this point, we know that the type of the returned object was not
171*4882a593Smuzhiyun 	 * one of the expected types for this predefined name. Attempt to
172*4882a593Smuzhiyun 	 * repair the object by converting it to one of the expected object
173*4882a593Smuzhiyun 	 * types for this predefined name.
174*4882a593Smuzhiyun 	 */
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	/*
177*4882a593Smuzhiyun 	 * If there is no return value, check if we require a return value for
178*4882a593Smuzhiyun 	 * this predefined name. Either one return value is expected, or none,
179*4882a593Smuzhiyun 	 * for both methods and other objects.
180*4882a593Smuzhiyun 	 *
181*4882a593Smuzhiyun 	 * Try to fix if there was no return object. Warning if failed to fix.
182*4882a593Smuzhiyun 	 */
183*4882a593Smuzhiyun 	if (!return_object) {
184*4882a593Smuzhiyun 		if (expected_btypes && (!(expected_btypes & ACPI_RTYPE_NONE))) {
185*4882a593Smuzhiyun 			if (package_index != ACPI_NOT_PACKAGE_ELEMENT) {
186*4882a593Smuzhiyun 				ACPI_WARN_PREDEFINED((AE_INFO,
187*4882a593Smuzhiyun 						      info->full_pathname,
188*4882a593Smuzhiyun 						      ACPI_WARN_ALWAYS,
189*4882a593Smuzhiyun 						      "Found unexpected NULL package element"));
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 				status =
192*4882a593Smuzhiyun 				    acpi_ns_repair_null_element(info,
193*4882a593Smuzhiyun 								expected_btypes,
194*4882a593Smuzhiyun 								package_index,
195*4882a593Smuzhiyun 								return_object_ptr);
196*4882a593Smuzhiyun 				if (ACPI_SUCCESS(status)) {
197*4882a593Smuzhiyun 					return (AE_OK);	/* Repair was successful */
198*4882a593Smuzhiyun 				}
199*4882a593Smuzhiyun 			} else {
200*4882a593Smuzhiyun 				ACPI_WARN_PREDEFINED((AE_INFO,
201*4882a593Smuzhiyun 						      info->full_pathname,
202*4882a593Smuzhiyun 						      ACPI_WARN_ALWAYS,
203*4882a593Smuzhiyun 						      "Missing expected return value"));
204*4882a593Smuzhiyun 			}
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 			return (AE_AML_NO_RETURN_VALUE);
207*4882a593Smuzhiyun 		}
208*4882a593Smuzhiyun 	}
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	if (expected_btypes & ACPI_RTYPE_INTEGER) {
211*4882a593Smuzhiyun 		status = acpi_ns_convert_to_integer(return_object, &new_object);
212*4882a593Smuzhiyun 		if (ACPI_SUCCESS(status)) {
213*4882a593Smuzhiyun 			goto object_repaired;
214*4882a593Smuzhiyun 		}
215*4882a593Smuzhiyun 	}
216*4882a593Smuzhiyun 	if (expected_btypes & ACPI_RTYPE_STRING) {
217*4882a593Smuzhiyun 		status = acpi_ns_convert_to_string(return_object, &new_object);
218*4882a593Smuzhiyun 		if (ACPI_SUCCESS(status)) {
219*4882a593Smuzhiyun 			goto object_repaired;
220*4882a593Smuzhiyun 		}
221*4882a593Smuzhiyun 	}
222*4882a593Smuzhiyun 	if (expected_btypes & ACPI_RTYPE_BUFFER) {
223*4882a593Smuzhiyun 		status = acpi_ns_convert_to_buffer(return_object, &new_object);
224*4882a593Smuzhiyun 		if (ACPI_SUCCESS(status)) {
225*4882a593Smuzhiyun 			goto object_repaired;
226*4882a593Smuzhiyun 		}
227*4882a593Smuzhiyun 	}
228*4882a593Smuzhiyun 	if (expected_btypes & ACPI_RTYPE_PACKAGE) {
229*4882a593Smuzhiyun 		/*
230*4882a593Smuzhiyun 		 * A package is expected. We will wrap the existing object with a
231*4882a593Smuzhiyun 		 * new package object. It is often the case that if a variable-length
232*4882a593Smuzhiyun 		 * package is required, but there is only a single object needed, the
233*4882a593Smuzhiyun 		 * BIOS will return that object instead of wrapping it with a Package
234*4882a593Smuzhiyun 		 * object. Note: after the wrapping, the package will be validated
235*4882a593Smuzhiyun 		 * for correct contents (expected object type or types).
236*4882a593Smuzhiyun 		 */
237*4882a593Smuzhiyun 		status =
238*4882a593Smuzhiyun 		    acpi_ns_wrap_with_package(info, return_object, &new_object);
239*4882a593Smuzhiyun 		if (ACPI_SUCCESS(status)) {
240*4882a593Smuzhiyun 			/*
241*4882a593Smuzhiyun 			 * The original object just had its reference count
242*4882a593Smuzhiyun 			 * incremented for being inserted into the new package.
243*4882a593Smuzhiyun 			 */
244*4882a593Smuzhiyun 			*return_object_ptr = new_object;	/* New Package object */
245*4882a593Smuzhiyun 			info->return_flags |= ACPI_OBJECT_REPAIRED;
246*4882a593Smuzhiyun 			return (AE_OK);
247*4882a593Smuzhiyun 		}
248*4882a593Smuzhiyun 	}
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	/* We cannot repair this object */
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	return (AE_AML_OPERAND_TYPE);
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun object_repaired:
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	/* Object was successfully repaired */
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	if (package_index != ACPI_NOT_PACKAGE_ELEMENT) {
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 		/* Update reference count of new object */
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 		if (!(info->return_flags & ACPI_OBJECT_WRAPPED)) {
263*4882a593Smuzhiyun 			new_object->common.reference_count =
264*4882a593Smuzhiyun 			    return_object->common.reference_count;
265*4882a593Smuzhiyun 		}
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 		ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
268*4882a593Smuzhiyun 				  "%s: Converted %s to expected %s at Package index %u\n",
269*4882a593Smuzhiyun 				  info->full_pathname,
270*4882a593Smuzhiyun 				  acpi_ut_get_object_type_name(return_object),
271*4882a593Smuzhiyun 				  acpi_ut_get_object_type_name(new_object),
272*4882a593Smuzhiyun 				  package_index));
273*4882a593Smuzhiyun 	} else {
274*4882a593Smuzhiyun 		ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
275*4882a593Smuzhiyun 				  "%s: Converted %s to expected %s\n",
276*4882a593Smuzhiyun 				  info->full_pathname,
277*4882a593Smuzhiyun 				  acpi_ut_get_object_type_name(return_object),
278*4882a593Smuzhiyun 				  acpi_ut_get_object_type_name(new_object)));
279*4882a593Smuzhiyun 	}
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	/* Delete old object, install the new return object */
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	acpi_ut_remove_reference(return_object);
284*4882a593Smuzhiyun 	*return_object_ptr = new_object;
285*4882a593Smuzhiyun 	info->return_flags |= ACPI_OBJECT_REPAIRED;
286*4882a593Smuzhiyun 	return (AE_OK);
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun /******************************************************************************
290*4882a593Smuzhiyun  *
291*4882a593Smuzhiyun  * FUNCTION:    acpi_ns_match_simple_repair
292*4882a593Smuzhiyun  *
293*4882a593Smuzhiyun  * PARAMETERS:  node                - Namespace node for the method/object
294*4882a593Smuzhiyun  *              return_btype        - Object type that was returned
295*4882a593Smuzhiyun  *              package_index       - Index of object within parent package (if
296*4882a593Smuzhiyun  *                                    applicable - ACPI_NOT_PACKAGE_ELEMENT
297*4882a593Smuzhiyun  *                                    otherwise)
298*4882a593Smuzhiyun  *
299*4882a593Smuzhiyun  * RETURN:      Pointer to entry in repair table. NULL indicates not found.
300*4882a593Smuzhiyun  *
301*4882a593Smuzhiyun  * DESCRIPTION: Check an object name against the repairable object list.
302*4882a593Smuzhiyun  *
303*4882a593Smuzhiyun  *****************************************************************************/
304*4882a593Smuzhiyun 
acpi_ns_match_simple_repair(struct acpi_namespace_node * node,u32 return_btype,u32 package_index)305*4882a593Smuzhiyun static const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct
306*4882a593Smuzhiyun 									 acpi_namespace_node
307*4882a593Smuzhiyun 									 *node,
308*4882a593Smuzhiyun 									 u32
309*4882a593Smuzhiyun 									 return_btype,
310*4882a593Smuzhiyun 									 u32
311*4882a593Smuzhiyun 									 package_index)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun 	const struct acpi_simple_repair_info *this_name;
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	/* Search info table for a repairable predefined method/object name */
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	this_name = acpi_object_repair_info;
318*4882a593Smuzhiyun 	while (this_name->object_converter) {
319*4882a593Smuzhiyun 		if (ACPI_COMPARE_NAMESEG(node->name.ascii, this_name->name)) {
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 			/* Check if we can actually repair this name/type combination */
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 			if ((return_btype & this_name->unexpected_btypes) &&
324*4882a593Smuzhiyun 			    (this_name->package_index ==
325*4882a593Smuzhiyun 			     ACPI_ALL_PACKAGE_ELEMENTS
326*4882a593Smuzhiyun 			     || package_index == this_name->package_index)) {
327*4882a593Smuzhiyun 				return (this_name);
328*4882a593Smuzhiyun 			}
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 			return (NULL);
331*4882a593Smuzhiyun 		}
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 		this_name++;
334*4882a593Smuzhiyun 	}
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	return (NULL);		/* Name was not found in the repair table */
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun /*******************************************************************************
340*4882a593Smuzhiyun  *
341*4882a593Smuzhiyun  * FUNCTION:    acpi_ns_repair_null_element
342*4882a593Smuzhiyun  *
343*4882a593Smuzhiyun  * PARAMETERS:  info                - Method execution information block
344*4882a593Smuzhiyun  *              expected_btypes     - Object types expected
345*4882a593Smuzhiyun  *              package_index       - Index of object within parent package (if
346*4882a593Smuzhiyun  *                                    applicable - ACPI_NOT_PACKAGE_ELEMENT
347*4882a593Smuzhiyun  *                                    otherwise)
348*4882a593Smuzhiyun  *              return_object_ptr   - Pointer to the object returned from the
349*4882a593Smuzhiyun  *                                    evaluation of a method or object
350*4882a593Smuzhiyun  *
351*4882a593Smuzhiyun  * RETURN:      Status. AE_OK if repair was successful.
352*4882a593Smuzhiyun  *
353*4882a593Smuzhiyun  * DESCRIPTION: Attempt to repair a NULL element of a returned Package object.
354*4882a593Smuzhiyun  *
355*4882a593Smuzhiyun  ******************************************************************************/
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun acpi_status
acpi_ns_repair_null_element(struct acpi_evaluate_info * info,u32 expected_btypes,u32 package_index,union acpi_operand_object ** return_object_ptr)358*4882a593Smuzhiyun acpi_ns_repair_null_element(struct acpi_evaluate_info *info,
359*4882a593Smuzhiyun 			    u32 expected_btypes,
360*4882a593Smuzhiyun 			    u32 package_index,
361*4882a593Smuzhiyun 			    union acpi_operand_object **return_object_ptr)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun 	union acpi_operand_object *return_object = *return_object_ptr;
364*4882a593Smuzhiyun 	union acpi_operand_object *new_object;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	ACPI_FUNCTION_NAME(ns_repair_null_element);
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	/* No repair needed if return object is non-NULL */
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	if (return_object) {
371*4882a593Smuzhiyun 		return (AE_OK);
372*4882a593Smuzhiyun 	}
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	/*
375*4882a593Smuzhiyun 	 * Attempt to repair a NULL element of a Package object. This applies to
376*4882a593Smuzhiyun 	 * predefined names that return a fixed-length package and each element
377*4882a593Smuzhiyun 	 * is required. It does not apply to variable-length packages where NULL
378*4882a593Smuzhiyun 	 * elements are allowed, especially at the end of the package.
379*4882a593Smuzhiyun 	 */
380*4882a593Smuzhiyun 	if (expected_btypes & ACPI_RTYPE_INTEGER) {
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 		/* Need an integer - create a zero-value integer */
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 		new_object = acpi_ut_create_integer_object((u64)0);
385*4882a593Smuzhiyun 	} else if (expected_btypes & ACPI_RTYPE_STRING) {
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 		/* Need a string - create a NULL string */
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 		new_object = acpi_ut_create_string_object(0);
390*4882a593Smuzhiyun 	} else if (expected_btypes & ACPI_RTYPE_BUFFER) {
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 		/* Need a buffer - create a zero-length buffer */
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 		new_object = acpi_ut_create_buffer_object(0);
395*4882a593Smuzhiyun 	} else {
396*4882a593Smuzhiyun 		/* Error for all other expected types */
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 		return (AE_AML_OPERAND_TYPE);
399*4882a593Smuzhiyun 	}
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	if (!new_object) {
402*4882a593Smuzhiyun 		return (AE_NO_MEMORY);
403*4882a593Smuzhiyun 	}
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	/* Set the reference count according to the parent Package object */
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	new_object->common.reference_count =
408*4882a593Smuzhiyun 	    info->parent_package->common.reference_count;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
411*4882a593Smuzhiyun 			  "%s: Converted NULL package element to expected %s at index %u\n",
412*4882a593Smuzhiyun 			  info->full_pathname,
413*4882a593Smuzhiyun 			  acpi_ut_get_object_type_name(new_object),
414*4882a593Smuzhiyun 			  package_index));
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	*return_object_ptr = new_object;
417*4882a593Smuzhiyun 	info->return_flags |= ACPI_OBJECT_REPAIRED;
418*4882a593Smuzhiyun 	return (AE_OK);
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun /******************************************************************************
422*4882a593Smuzhiyun  *
423*4882a593Smuzhiyun  * FUNCTION:    acpi_ns_remove_null_elements
424*4882a593Smuzhiyun  *
425*4882a593Smuzhiyun  * PARAMETERS:  info                - Method execution information block
426*4882a593Smuzhiyun  *              package_type        - An acpi_return_package_types value
427*4882a593Smuzhiyun  *              obj_desc            - A Package object
428*4882a593Smuzhiyun  *
429*4882a593Smuzhiyun  * RETURN:      None.
430*4882a593Smuzhiyun  *
431*4882a593Smuzhiyun  * DESCRIPTION: Remove all NULL package elements from packages that contain
432*4882a593Smuzhiyun  *              a variable number of subpackages. For these types of
433*4882a593Smuzhiyun  *              packages, NULL elements can be safely removed.
434*4882a593Smuzhiyun  *
435*4882a593Smuzhiyun  *****************************************************************************/
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun void
acpi_ns_remove_null_elements(struct acpi_evaluate_info * info,u8 package_type,union acpi_operand_object * obj_desc)438*4882a593Smuzhiyun acpi_ns_remove_null_elements(struct acpi_evaluate_info *info,
439*4882a593Smuzhiyun 			     u8 package_type,
440*4882a593Smuzhiyun 			     union acpi_operand_object *obj_desc)
441*4882a593Smuzhiyun {
442*4882a593Smuzhiyun 	union acpi_operand_object **source;
443*4882a593Smuzhiyun 	union acpi_operand_object **dest;
444*4882a593Smuzhiyun 	u32 count;
445*4882a593Smuzhiyun 	u32 new_count;
446*4882a593Smuzhiyun 	u32 i;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	ACPI_FUNCTION_NAME(ns_remove_null_elements);
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	/*
451*4882a593Smuzhiyun 	 * We can safely remove all NULL elements from these package types:
452*4882a593Smuzhiyun 	 * PTYPE1_VAR packages contain a variable number of simple data types.
453*4882a593Smuzhiyun 	 * PTYPE2 packages contain a variable number of subpackages.
454*4882a593Smuzhiyun 	 */
455*4882a593Smuzhiyun 	switch (package_type) {
456*4882a593Smuzhiyun 	case ACPI_PTYPE1_VAR:
457*4882a593Smuzhiyun 	case ACPI_PTYPE2:
458*4882a593Smuzhiyun 	case ACPI_PTYPE2_COUNT:
459*4882a593Smuzhiyun 	case ACPI_PTYPE2_PKG_COUNT:
460*4882a593Smuzhiyun 	case ACPI_PTYPE2_FIXED:
461*4882a593Smuzhiyun 	case ACPI_PTYPE2_MIN:
462*4882a593Smuzhiyun 	case ACPI_PTYPE2_REV_FIXED:
463*4882a593Smuzhiyun 	case ACPI_PTYPE2_FIX_VAR:
464*4882a593Smuzhiyun 		break;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	default:
467*4882a593Smuzhiyun 	case ACPI_PTYPE2_VAR_VAR:
468*4882a593Smuzhiyun 	case ACPI_PTYPE1_FIXED:
469*4882a593Smuzhiyun 	case ACPI_PTYPE1_OPTION:
470*4882a593Smuzhiyun 		return;
471*4882a593Smuzhiyun 	}
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	count = obj_desc->package.count;
474*4882a593Smuzhiyun 	new_count = count;
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	source = obj_desc->package.elements;
477*4882a593Smuzhiyun 	dest = source;
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	/* Examine all elements of the package object, remove nulls */
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	for (i = 0; i < count; i++) {
482*4882a593Smuzhiyun 		if (!*source) {
483*4882a593Smuzhiyun 			new_count--;
484*4882a593Smuzhiyun 		} else {
485*4882a593Smuzhiyun 			*dest = *source;
486*4882a593Smuzhiyun 			dest++;
487*4882a593Smuzhiyun 		}
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 		source++;
490*4882a593Smuzhiyun 	}
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	/* Update parent package if any null elements were removed */
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	if (new_count < count) {
495*4882a593Smuzhiyun 		ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
496*4882a593Smuzhiyun 				  "%s: Found and removed %u NULL elements\n",
497*4882a593Smuzhiyun 				  info->full_pathname, (count - new_count)));
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 		/* NULL terminate list and update the package count */
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 		*dest = NULL;
502*4882a593Smuzhiyun 		obj_desc->package.count = new_count;
503*4882a593Smuzhiyun 	}
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun /*******************************************************************************
507*4882a593Smuzhiyun  *
508*4882a593Smuzhiyun  * FUNCTION:    acpi_ns_wrap_with_package
509*4882a593Smuzhiyun  *
510*4882a593Smuzhiyun  * PARAMETERS:  info                - Method execution information block
511*4882a593Smuzhiyun  *              original_object     - Pointer to the object to repair.
512*4882a593Smuzhiyun  *              obj_desc_ptr        - The new package object is returned here
513*4882a593Smuzhiyun  *
514*4882a593Smuzhiyun  * RETURN:      Status, new object in *obj_desc_ptr
515*4882a593Smuzhiyun  *
516*4882a593Smuzhiyun  * DESCRIPTION: Repair a common problem with objects that are defined to
517*4882a593Smuzhiyun  *              return a variable-length Package of sub-objects. If there is
518*4882a593Smuzhiyun  *              only one sub-object, some BIOS code mistakenly simply declares
519*4882a593Smuzhiyun  *              the single object instead of a Package with one sub-object.
520*4882a593Smuzhiyun  *              This function attempts to repair this error by wrapping a
521*4882a593Smuzhiyun  *              Package object around the original object, creating the
522*4882a593Smuzhiyun  *              correct and expected Package with one sub-object.
523*4882a593Smuzhiyun  *
524*4882a593Smuzhiyun  *              Names that can be repaired in this manner include:
525*4882a593Smuzhiyun  *              _ALR, _CSD, _HPX, _MLS, _PLD, _PRT, _PSS, _TRT, _TSS,
526*4882a593Smuzhiyun  *              _BCL, _DOD, _FIX, _Sx
527*4882a593Smuzhiyun  *
528*4882a593Smuzhiyun  ******************************************************************************/
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun acpi_status
acpi_ns_wrap_with_package(struct acpi_evaluate_info * info,union acpi_operand_object * original_object,union acpi_operand_object ** obj_desc_ptr)531*4882a593Smuzhiyun acpi_ns_wrap_with_package(struct acpi_evaluate_info *info,
532*4882a593Smuzhiyun 			  union acpi_operand_object *original_object,
533*4882a593Smuzhiyun 			  union acpi_operand_object **obj_desc_ptr)
534*4882a593Smuzhiyun {
535*4882a593Smuzhiyun 	union acpi_operand_object *pkg_obj_desc;
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	ACPI_FUNCTION_NAME(ns_wrap_with_package);
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	/*
540*4882a593Smuzhiyun 	 * Create the new outer package and populate it. The new
541*4882a593Smuzhiyun 	 * package will have a single element, the lone sub-object.
542*4882a593Smuzhiyun 	 */
543*4882a593Smuzhiyun 	pkg_obj_desc = acpi_ut_create_package_object(1);
544*4882a593Smuzhiyun 	if (!pkg_obj_desc) {
545*4882a593Smuzhiyun 		return (AE_NO_MEMORY);
546*4882a593Smuzhiyun 	}
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	pkg_obj_desc->package.elements[0] = original_object;
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
551*4882a593Smuzhiyun 			  "%s: Wrapped %s with expected Package object\n",
552*4882a593Smuzhiyun 			  info->full_pathname,
553*4882a593Smuzhiyun 			  acpi_ut_get_object_type_name(original_object)));
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	/* Return the new object in the object pointer */
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	*obj_desc_ptr = pkg_obj_desc;
558*4882a593Smuzhiyun 	info->return_flags |= ACPI_OBJECT_REPAIRED | ACPI_OBJECT_WRAPPED;
559*4882a593Smuzhiyun 	return (AE_OK);
560*4882a593Smuzhiyun }
561