Commit | Line | Data |
---|---|---|
b2deadd5 BM |
1 | /****************************************************************************** |
2 | * | |
3 | * Module Name: nsrepair - Repair for objects returned by predefined methods | |
4 | * | |
5 | *****************************************************************************/ | |
6 | ||
7 | /* | |
77848130 | 8 | * Copyright (C) 2000 - 2012, Intel Corp. |
b2deadd5 BM |
9 | * All rights reserved. |
10 | * | |
11 | * Redistribution and use in source and binary forms, with or without | |
12 | * modification, are permitted provided that the following conditions | |
13 | * are met: | |
14 | * 1. Redistributions of source code must retain the above copyright | |
15 | * notice, this list of conditions, and the following disclaimer, | |
16 | * without modification. | |
17 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | |
18 | * substantially similar to the "NO WARRANTY" disclaimer below | |
19 | * ("Disclaimer") and any redistribution must be conditioned upon | |
20 | * including a substantially similar Disclaimer requirement for further | |
21 | * binary redistribution. | |
22 | * 3. Neither the names of the above-listed copyright holders nor the names | |
23 | * of any contributors may be used to endorse or promote products derived | |
24 | * from this software without specific prior written permission. | |
25 | * | |
26 | * Alternatively, this software may be distributed under the terms of the | |
27 | * GNU General Public License ("GPL") version 2 as published by the Free | |
28 | * Software Foundation. | |
29 | * | |
30 | * NO WARRANTY | |
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | |
34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
35 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
36 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
37 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
40 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
41 | * POSSIBILITY OF SUCH DAMAGES. | |
42 | */ | |
43 | ||
44 | #include <acpi/acpi.h> | |
45 | #include "accommon.h" | |
46 | #include "acnamesp.h" | |
0240d7b4 | 47 | #include "acinterp.h" |
091f4d71 | 48 | #include "acpredef.h" |
b2deadd5 BM |
49 | |
50 | #define _COMPONENT ACPI_NAMESPACE | |
51 | ACPI_MODULE_NAME("nsrepair") | |
52 | ||
47e11d54 BM |
53 | /******************************************************************************* |
54 | * | |
55 | * This module attempts to repair or convert objects returned by the | |
56 | * predefined methods to an object type that is expected, as per the ACPI | |
57 | * specification. The need for this code is dictated by the many machines that | |
58 | * return incorrect types for the standard predefined methods. Performing these | |
59 | * conversions here, in one place, eliminates the need for individual ACPI | |
60 | * device drivers to do the same. Note: Most of these conversions are different | |
61 | * than the internal object conversion routines used for implicit object | |
62 | * conversion. | |
63 | * | |
64 | * The following conversions can be performed as necessary: | |
65 | * | |
66 | * Integer -> String | |
67 | * Integer -> Buffer | |
68 | * String -> Integer | |
69 | * String -> Buffer | |
70 | * Buffer -> Integer | |
71 | * Buffer -> String | |
72 | * Buffer -> Package of Integers | |
73 | * Package -> Package of one Package | |
6a99b1c9 | 74 | * An incorrect standalone object is wrapped with required outer package |
47e11d54 | 75 | * |
091f4d71 | 76 | * Additional possible repairs: |
091f4d71 | 77 | * Required package elements that are NULL replaced by Integer/String/Buffer |
091f4d71 | 78 | * |
47e11d54 BM |
79 | ******************************************************************************/ |
80 | /* Local prototypes */ | |
81 | static acpi_status | |
82 | acpi_ns_convert_to_integer(union acpi_operand_object *original_object, | |
83 | union acpi_operand_object **return_object); | |
84 | ||
85 | static acpi_status | |
86 | acpi_ns_convert_to_string(union acpi_operand_object *original_object, | |
87 | union acpi_operand_object **return_object); | |
88 | ||
89 | static acpi_status | |
90 | acpi_ns_convert_to_buffer(union acpi_operand_object *original_object, | |
91 | union acpi_operand_object **return_object); | |
92 | ||
b2deadd5 BM |
93 | /******************************************************************************* |
94 | * | |
95 | * FUNCTION: acpi_ns_repair_object | |
96 | * | |
ba494bee | 97 | * PARAMETERS: data - Pointer to validation data structure |
b2deadd5 BM |
98 | * expected_btypes - Object types expected |
99 | * package_index - Index of object within parent package (if | |
100 | * applicable - ACPI_NOT_PACKAGE_ELEMENT | |
101 | * otherwise) | |
102 | * return_object_ptr - Pointer to the object returned from the | |
103 | * evaluation of a method or object | |
104 | * | |
105 | * RETURN: Status. AE_OK if repair was successful. | |
106 | * | |
107 | * DESCRIPTION: Attempt to repair/convert a return object of a type that was | |
108 | * not expected. | |
109 | * | |
110 | ******************************************************************************/ | |
47e11d54 | 111 | |
b2deadd5 BM |
112 | acpi_status |
113 | acpi_ns_repair_object(struct acpi_predefined_data *data, | |
114 | u32 expected_btypes, | |
115 | u32 package_index, | |
116 | union acpi_operand_object **return_object_ptr) | |
117 | { | |
118 | union acpi_operand_object *return_object = *return_object_ptr; | |
119 | union acpi_operand_object *new_object; | |
0240d7b4 | 120 | acpi_status status; |
b2deadd5 | 121 | |
3a58176e BM |
122 | ACPI_FUNCTION_NAME(ns_repair_object); |
123 | ||
27526993 BM |
124 | /* |
125 | * At this point, we know that the type of the returned object was not | |
126 | * one of the expected types for this predefined name. Attempt to | |
47e11d54 BM |
127 | * repair the object by converting it to one of the expected object |
128 | * types for this predefined name. | |
129 | */ | |
130 | if (expected_btypes & ACPI_RTYPE_INTEGER) { | |
131 | status = acpi_ns_convert_to_integer(return_object, &new_object); | |
132 | if (ACPI_SUCCESS(status)) { | |
133 | goto object_repaired; | |
134 | } | |
135 | } | |
136 | if (expected_btypes & ACPI_RTYPE_STRING) { | |
137 | status = acpi_ns_convert_to_string(return_object, &new_object); | |
138 | if (ACPI_SUCCESS(status)) { | |
139 | goto object_repaired; | |
140 | } | |
141 | } | |
142 | if (expected_btypes & ACPI_RTYPE_BUFFER) { | |
143 | status = acpi_ns_convert_to_buffer(return_object, &new_object); | |
144 | if (ACPI_SUCCESS(status)) { | |
145 | goto object_repaired; | |
146 | } | |
147 | } | |
148 | if (expected_btypes & ACPI_RTYPE_PACKAGE) { | |
6a99b1c9 BM |
149 | /* |
150 | * A package is expected. We will wrap the existing object with a | |
151 | * new package object. It is often the case that if a variable-length | |
152 | * package is required, but there is only a single object needed, the | |
153 | * BIOS will return that object instead of wrapping it with a Package | |
154 | * object. Note: after the wrapping, the package will be validated | |
155 | * for correct contents (expected object type or types). | |
156 | */ | |
157 | status = | |
158 | acpi_ns_wrap_with_package(data, return_object, &new_object); | |
47e11d54 | 159 | if (ACPI_SUCCESS(status)) { |
6a99b1c9 BM |
160 | /* |
161 | * The original object just had its reference count | |
162 | * incremented for being inserted into the new package. | |
163 | */ | |
164 | *return_object_ptr = new_object; /* New Package object */ | |
165 | data->flags |= ACPI_OBJECT_REPAIRED; | |
166 | return (AE_OK); | |
47e11d54 BM |
167 | } |
168 | } | |
169 | ||
170 | /* We cannot repair this object */ | |
171 | ||
172 | return (AE_AML_OPERAND_TYPE); | |
173 | ||
174 | object_repaired: | |
175 | ||
176 | /* Object was successfully repaired */ | |
177 | ||
47e11d54 | 178 | if (package_index != ACPI_NOT_PACKAGE_ELEMENT) { |
6a99b1c9 BM |
179 | /* |
180 | * The original object is a package element. We need to | |
181 | * decrement the reference count of the original object, | |
182 | * for removing it from the package. | |
183 | * | |
184 | * However, if the original object was just wrapped with a | |
185 | * package object as part of the repair, we don't need to | |
186 | * change the reference count. | |
187 | */ | |
188 | if (!(data->flags & ACPI_OBJECT_WRAPPED)) { | |
189 | new_object->common.reference_count = | |
190 | return_object->common.reference_count; | |
47e11d54 | 191 | |
6a99b1c9 BM |
192 | if (return_object->common.reference_count > 1) { |
193 | return_object->common.reference_count--; | |
194 | } | |
47e11d54 BM |
195 | } |
196 | ||
3a58176e | 197 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
6a99b1c9 | 198 | "%s: Converted %s to expected %s at Package index %u\n", |
3a58176e BM |
199 | data->pathname, |
200 | acpi_ut_get_object_type_name(return_object), | |
201 | acpi_ut_get_object_type_name(new_object), | |
202 | package_index)); | |
47e11d54 | 203 | } else { |
3a58176e BM |
204 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
205 | "%s: Converted %s to expected %s\n", | |
206 | data->pathname, | |
207 | acpi_ut_get_object_type_name(return_object), | |
208 | acpi_ut_get_object_type_name(new_object))); | |
47e11d54 BM |
209 | } |
210 | ||
211 | /* Delete old object, install the new return object */ | |
212 | ||
213 | acpi_ut_remove_reference(return_object); | |
214 | *return_object_ptr = new_object; | |
215 | data->flags |= ACPI_OBJECT_REPAIRED; | |
216 | return (AE_OK); | |
217 | } | |
218 | ||
219 | /******************************************************************************* | |
220 | * | |
221 | * FUNCTION: acpi_ns_convert_to_integer | |
222 | * | |
223 | * PARAMETERS: original_object - Object to be converted | |
224 | * return_object - Where the new converted object is returned | |
225 | * | |
226 | * RETURN: Status. AE_OK if conversion was successful. | |
227 | * | |
228 | * DESCRIPTION: Attempt to convert a String/Buffer object to an Integer. | |
229 | * | |
230 | ******************************************************************************/ | |
231 | ||
232 | static acpi_status | |
233 | acpi_ns_convert_to_integer(union acpi_operand_object *original_object, | |
234 | union acpi_operand_object **return_object) | |
235 | { | |
236 | union acpi_operand_object *new_object; | |
237 | acpi_status status; | |
238 | u64 value = 0; | |
239 | u32 i; | |
240 | ||
241 | switch (original_object->common.type) { | |
242 | case ACPI_TYPE_STRING: | |
243 | ||
244 | /* String-to-Integer conversion */ | |
245 | ||
246 | status = acpi_ut_strtoul64(original_object->string.pointer, | |
247 | ACPI_ANY_BASE, &value); | |
248 | if (ACPI_FAILURE(status)) { | |
249 | return (status); | |
250 | } | |
251 | break; | |
252 | ||
b2deadd5 BM |
253 | case ACPI_TYPE_BUFFER: |
254 | ||
47e11d54 | 255 | /* Buffer-to-Integer conversion. Max buffer size is 64 bits. */ |
b2deadd5 | 256 | |
47e11d54 | 257 | if (original_object->buffer.length > 8) { |
b2deadd5 BM |
258 | return (AE_AML_OPERAND_TYPE); |
259 | } | |
260 | ||
47e11d54 BM |
261 | /* Extract each buffer byte to create the integer */ |
262 | ||
263 | for (i = 0; i < original_object->buffer.length; i++) { | |
264 | value |= | |
265 | ((u64) original_object->buffer. | |
266 | pointer[i] << (i * 8)); | |
267 | } | |
268 | break; | |
269 | ||
270 | default: | |
271 | return (AE_AML_OPERAND_TYPE); | |
272 | } | |
273 | ||
274 | new_object = acpi_ut_create_integer_object(value); | |
275 | if (!new_object) { | |
276 | return (AE_NO_MEMORY); | |
277 | } | |
278 | ||
279 | *return_object = new_object; | |
280 | return (AE_OK); | |
281 | } | |
282 | ||
283 | /******************************************************************************* | |
284 | * | |
285 | * FUNCTION: acpi_ns_convert_to_string | |
286 | * | |
287 | * PARAMETERS: original_object - Object to be converted | |
288 | * return_object - Where the new converted object is returned | |
289 | * | |
290 | * RETURN: Status. AE_OK if conversion was successful. | |
291 | * | |
292 | * DESCRIPTION: Attempt to convert a Integer/Buffer object to a String. | |
293 | * | |
294 | ******************************************************************************/ | |
295 | ||
296 | static acpi_status | |
297 | acpi_ns_convert_to_string(union acpi_operand_object *original_object, | |
298 | union acpi_operand_object **return_object) | |
299 | { | |
300 | union acpi_operand_object *new_object; | |
301 | acpi_size length; | |
302 | acpi_status status; | |
303 | ||
304 | switch (original_object->common.type) { | |
305 | case ACPI_TYPE_INTEGER: | |
b2deadd5 | 306 | /* |
47e11d54 BM |
307 | * Integer-to-String conversion. Commonly, convert |
308 | * an integer of value 0 to a NULL string. The last element of | |
309 | * _BIF and _BIX packages occasionally need this fix. | |
310 | */ | |
311 | if (original_object->integer.value == 0) { | |
312 | ||
313 | /* Allocate a new NULL string object */ | |
314 | ||
315 | new_object = acpi_ut_create_string_object(0); | |
316 | if (!new_object) { | |
317 | return (AE_NO_MEMORY); | |
318 | } | |
319 | } else { | |
320 | status = | |
321 | acpi_ex_convert_to_string(original_object, | |
322 | &new_object, | |
323 | ACPI_IMPLICIT_CONVERT_HEX); | |
324 | if (ACPI_FAILURE(status)) { | |
325 | return (status); | |
326 | } | |
327 | } | |
328 | break; | |
329 | ||
330 | case ACPI_TYPE_BUFFER: | |
331 | /* | |
332 | * Buffer-to-String conversion. Use a to_string | |
b2deadd5 BM |
333 | * conversion, no transform performed on the buffer data. The best |
334 | * example of this is the _BIF method, where the string data from | |
335 | * the battery is often (incorrectly) returned as buffer object(s). | |
336 | */ | |
337 | length = 0; | |
47e11d54 BM |
338 | while ((length < original_object->buffer.length) && |
339 | (original_object->buffer.pointer[length])) { | |
b2deadd5 BM |
340 | length++; |
341 | } | |
342 | ||
343 | /* Allocate a new string object */ | |
344 | ||
345 | new_object = acpi_ut_create_string_object(length); | |
346 | if (!new_object) { | |
347 | return (AE_NO_MEMORY); | |
348 | } | |
349 | ||
350 | /* | |
351 | * Copy the raw buffer data with no transform. String is already NULL | |
352 | * terminated at Length+1. | |
353 | */ | |
354 | ACPI_MEMCPY(new_object->string.pointer, | |
47e11d54 | 355 | original_object->buffer.pointer, length); |
27526993 | 356 | break; |
b2deadd5 | 357 | |
47e11d54 BM |
358 | default: |
359 | return (AE_AML_OPERAND_TYPE); | |
360 | } | |
27526993 | 361 | |
47e11d54 BM |
362 | *return_object = new_object; |
363 | return (AE_OK); | |
364 | } | |
0240d7b4 | 365 | |
47e11d54 BM |
366 | /******************************************************************************* |
367 | * | |
368 | * FUNCTION: acpi_ns_convert_to_buffer | |
369 | * | |
370 | * PARAMETERS: original_object - Object to be converted | |
371 | * return_object - Where the new converted object is returned | |
372 | * | |
373 | * RETURN: Status. AE_OK if conversion was successful. | |
374 | * | |
ea7c5ec1 | 375 | * DESCRIPTION: Attempt to convert a Integer/String/Package object to a Buffer. |
47e11d54 BM |
376 | * |
377 | ******************************************************************************/ | |
0240d7b4 | 378 | |
47e11d54 BM |
379 | static acpi_status |
380 | acpi_ns_convert_to_buffer(union acpi_operand_object *original_object, | |
381 | union acpi_operand_object **return_object) | |
382 | { | |
383 | union acpi_operand_object *new_object; | |
384 | acpi_status status; | |
ea7c5ec1 BM |
385 | union acpi_operand_object **elements; |
386 | u32 *dword_buffer; | |
387 | u32 count; | |
388 | u32 i; | |
b2deadd5 | 389 | |
47e11d54 BM |
390 | switch (original_object->common.type) { |
391 | case ACPI_TYPE_INTEGER: | |
392 | /* | |
393 | * Integer-to-Buffer conversion. | |
394 | * Convert the Integer to a packed-byte buffer. _MAT and other | |
395 | * objects need this sometimes, if a read has been performed on a | |
396 | * Field object that is less than or equal to the global integer | |
397 | * size (32 or 64 bits). | |
398 | */ | |
399 | status = | |
400 | acpi_ex_convert_to_buffer(original_object, &new_object); | |
401 | if (ACPI_FAILURE(status)) { | |
402 | return (status); | |
403 | } | |
404 | break; | |
b2deadd5 | 405 | |
47e11d54 | 406 | case ACPI_TYPE_STRING: |
27526993 | 407 | |
47e11d54 BM |
408 | /* String-to-Buffer conversion. Simple data copy */ |
409 | ||
410 | new_object = | |
411 | acpi_ut_create_buffer_object(original_object->string. | |
412 | length); | |
413 | if (!new_object) { | |
414 | return (AE_NO_MEMORY); | |
b2deadd5 | 415 | } |
47e11d54 BM |
416 | |
417 | ACPI_MEMCPY(new_object->buffer.pointer, | |
418 | original_object->string.pointer, | |
419 | original_object->string.length); | |
27526993 | 420 | break; |
b2deadd5 | 421 | |
ea7c5ec1 | 422 | case ACPI_TYPE_PACKAGE: |
43420bbb BM |
423 | /* |
424 | * This case is often seen for predefined names that must return a | |
425 | * Buffer object with multiple DWORD integers within. For example, | |
426 | * _FDE and _GTM. The Package can be converted to a Buffer. | |
427 | */ | |
ea7c5ec1 BM |
428 | |
429 | /* All elements of the Package must be integers */ | |
430 | ||
431 | elements = original_object->package.elements; | |
432 | count = original_object->package.count; | |
433 | ||
434 | for (i = 0; i < count; i++) { | |
435 | if ((!*elements) || | |
436 | ((*elements)->common.type != ACPI_TYPE_INTEGER)) { | |
437 | return (AE_AML_OPERAND_TYPE); | |
438 | } | |
439 | elements++; | |
440 | } | |
441 | ||
442 | /* Create the new buffer object to replace the Package */ | |
443 | ||
444 | new_object = acpi_ut_create_buffer_object(ACPI_MUL_4(count)); | |
445 | if (!new_object) { | |
446 | return (AE_NO_MEMORY); | |
447 | } | |
448 | ||
449 | /* Copy the package elements (integers) to the buffer as DWORDs */ | |
450 | ||
451 | elements = original_object->package.elements; | |
452 | dword_buffer = ACPI_CAST_PTR(u32, new_object->buffer.pointer); | |
453 | ||
454 | for (i = 0; i < count; i++) { | |
455 | *dword_buffer = (u32) (*elements)->integer.value; | |
456 | dword_buffer++; | |
457 | elements++; | |
458 | } | |
459 | break; | |
460 | ||
27526993 | 461 | default: |
27526993 | 462 | return (AE_AML_OPERAND_TYPE); |
b2deadd5 BM |
463 | } |
464 | ||
47e11d54 BM |
465 | *return_object = new_object; |
466 | return (AE_OK); | |
467 | } | |
27526993 | 468 | |
091f4d71 BM |
469 | /******************************************************************************* |
470 | * | |
471 | * FUNCTION: acpi_ns_repair_null_element | |
472 | * | |
ba494bee | 473 | * PARAMETERS: data - Pointer to validation data structure |
091f4d71 BM |
474 | * expected_btypes - Object types expected |
475 | * package_index - Index of object within parent package (if | |
476 | * applicable - ACPI_NOT_PACKAGE_ELEMENT | |
477 | * otherwise) | |
478 | * return_object_ptr - Pointer to the object returned from the | |
479 | * evaluation of a method or object | |
480 | * | |
481 | * RETURN: Status. AE_OK if repair was successful. | |
482 | * | |
483 | * DESCRIPTION: Attempt to repair a NULL element of a returned Package object. | |
484 | * | |
485 | ******************************************************************************/ | |
486 | ||
487 | acpi_status | |
488 | acpi_ns_repair_null_element(struct acpi_predefined_data *data, | |
489 | u32 expected_btypes, | |
490 | u32 package_index, | |
491 | union acpi_operand_object **return_object_ptr) | |
492 | { | |
493 | union acpi_operand_object *return_object = *return_object_ptr; | |
494 | union acpi_operand_object *new_object; | |
495 | ||
496 | ACPI_FUNCTION_NAME(ns_repair_null_element); | |
497 | ||
498 | /* No repair needed if return object is non-NULL */ | |
499 | ||
500 | if (return_object) { | |
501 | return (AE_OK); | |
502 | } | |
503 | ||
504 | /* | |
505 | * Attempt to repair a NULL element of a Package object. This applies to | |
506 | * predefined names that return a fixed-length package and each element | |
507 | * is required. It does not apply to variable-length packages where NULL | |
508 | * elements are allowed, especially at the end of the package. | |
509 | */ | |
510 | if (expected_btypes & ACPI_RTYPE_INTEGER) { | |
511 | ||
ba494bee | 512 | /* Need an integer - create a zero-value integer */ |
091f4d71 | 513 | |
150dba38 | 514 | new_object = acpi_ut_create_integer_object((u64)0); |
091f4d71 BM |
515 | } else if (expected_btypes & ACPI_RTYPE_STRING) { |
516 | ||
ba494bee | 517 | /* Need a string - create a NULL string */ |
091f4d71 BM |
518 | |
519 | new_object = acpi_ut_create_string_object(0); | |
520 | } else if (expected_btypes & ACPI_RTYPE_BUFFER) { | |
521 | ||
ba494bee | 522 | /* Need a buffer - create a zero-length buffer */ |
091f4d71 BM |
523 | |
524 | new_object = acpi_ut_create_buffer_object(0); | |
525 | } else { | |
526 | /* Error for all other expected types */ | |
527 | ||
528 | return (AE_AML_OPERAND_TYPE); | |
529 | } | |
530 | ||
531 | if (!new_object) { | |
532 | return (AE_NO_MEMORY); | |
533 | } | |
534 | ||
535 | /* Set the reference count according to the parent Package object */ | |
536 | ||
537 | new_object->common.reference_count = | |
538 | data->parent_package->common.reference_count; | |
539 | ||
540 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, | |
541 | "%s: Converted NULL package element to expected %s at index %u\n", | |
542 | data->pathname, | |
543 | acpi_ut_get_object_type_name(new_object), | |
544 | package_index)); | |
545 | ||
546 | *return_object_ptr = new_object; | |
547 | data->flags |= ACPI_OBJECT_REPAIRED; | |
548 | return (AE_OK); | |
549 | } | |
550 | ||
551 | /****************************************************************************** | |
552 | * | |
553 | * FUNCTION: acpi_ns_remove_null_elements | |
554 | * | |
ba494bee | 555 | * PARAMETERS: data - Pointer to validation data structure |
091f4d71 BM |
556 | * package_type - An acpi_return_package_types value |
557 | * obj_desc - A Package object | |
558 | * | |
559 | * RETURN: None. | |
560 | * | |
561 | * DESCRIPTION: Remove all NULL package elements from packages that contain | |
562 | * a variable number of sub-packages. For these types of | |
563 | * packages, NULL elements can be safely removed. | |
564 | * | |
565 | *****************************************************************************/ | |
566 | ||
567 | void | |
568 | acpi_ns_remove_null_elements(struct acpi_predefined_data *data, | |
569 | u8 package_type, | |
570 | union acpi_operand_object *obj_desc) | |
571 | { | |
572 | union acpi_operand_object **source; | |
573 | union acpi_operand_object **dest; | |
574 | u32 count; | |
575 | u32 new_count; | |
576 | u32 i; | |
577 | ||
578 | ACPI_FUNCTION_NAME(ns_remove_null_elements); | |
579 | ||
580 | /* | |
945488b9 BM |
581 | * We can safely remove all NULL elements from these package types: |
582 | * PTYPE1_VAR packages contain a variable number of simple data types. | |
583 | * PTYPE2 packages contain a variable number of sub-packages. | |
091f4d71 BM |
584 | */ |
585 | switch (package_type) { | |
091f4d71 | 586 | case ACPI_PTYPE1_VAR: |
091f4d71 BM |
587 | case ACPI_PTYPE2: |
588 | case ACPI_PTYPE2_COUNT: | |
589 | case ACPI_PTYPE2_PKG_COUNT: | |
590 | case ACPI_PTYPE2_FIXED: | |
591 | case ACPI_PTYPE2_MIN: | |
592 | case ACPI_PTYPE2_REV_FIXED: | |
7fce7a4b | 593 | case ACPI_PTYPE2_FIX_VAR: |
091f4d71 BM |
594 | break; |
595 | ||
596 | default: | |
945488b9 BM |
597 | case ACPI_PTYPE1_FIXED: |
598 | case ACPI_PTYPE1_OPTION: | |
091f4d71 BM |
599 | return; |
600 | } | |
601 | ||
602 | count = obj_desc->package.count; | |
603 | new_count = count; | |
604 | ||
605 | source = obj_desc->package.elements; | |
606 | dest = source; | |
607 | ||
608 | /* Examine all elements of the package object, remove nulls */ | |
609 | ||
610 | for (i = 0; i < count; i++) { | |
611 | if (!*source) { | |
612 | new_count--; | |
613 | } else { | |
614 | *dest = *source; | |
615 | dest++; | |
616 | } | |
617 | source++; | |
618 | } | |
619 | ||
620 | /* Update parent package if any null elements were removed */ | |
621 | ||
622 | if (new_count < count) { | |
623 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, | |
624 | "%s: Found and removed %u NULL elements\n", | |
625 | data->pathname, (count - new_count))); | |
626 | ||
627 | /* NULL terminate list and update the package count */ | |
628 | ||
629 | *dest = NULL; | |
630 | obj_desc->package.count = new_count; | |
631 | } | |
632 | } | |
633 | ||
e5f69d6e BM |
634 | /******************************************************************************* |
635 | * | |
6a99b1c9 | 636 | * FUNCTION: acpi_ns_wrap_with_package |
e5f69d6e | 637 | * |
ba494bee | 638 | * PARAMETERS: data - Pointer to validation data structure |
6a99b1c9 BM |
639 | * original_object - Pointer to the object to repair. |
640 | * obj_desc_ptr - The new package object is returned here | |
e5f69d6e BM |
641 | * |
642 | * RETURN: Status, new object in *obj_desc_ptr | |
643 | * | |
6a99b1c9 BM |
644 | * DESCRIPTION: Repair a common problem with objects that are defined to |
645 | * return a variable-length Package of sub-objects. If there is | |
646 | * only one sub-object, some BIOS code mistakenly simply declares | |
647 | * the single object instead of a Package with one sub-object. | |
648 | * This function attempts to repair this error by wrapping a | |
649 | * Package object around the original object, creating the | |
650 | * correct and expected Package with one sub-object. | |
e5f69d6e BM |
651 | * |
652 | * Names that can be repaired in this manner include: | |
6a99b1c9 BM |
653 | * _ALR, _CSD, _HPX, _MLS, _PLD, _PRT, _PSS, _TRT, _TSS, |
654 | * _BCL, _DOD, _FIX, _Sx | |
e5f69d6e BM |
655 | * |
656 | ******************************************************************************/ | |
657 | ||
658 | acpi_status | |
6a99b1c9 BM |
659 | acpi_ns_wrap_with_package(struct acpi_predefined_data *data, |
660 | union acpi_operand_object *original_object, | |
661 | union acpi_operand_object **obj_desc_ptr) | |
e5f69d6e BM |
662 | { |
663 | union acpi_operand_object *pkg_obj_desc; | |
664 | ||
6a99b1c9 | 665 | ACPI_FUNCTION_NAME(ns_wrap_with_package); |
3a58176e | 666 | |
e5f69d6e BM |
667 | /* |
668 | * Create the new outer package and populate it. The new package will | |
6a99b1c9 | 669 | * have a single element, the lone sub-object. |
e5f69d6e BM |
670 | */ |
671 | pkg_obj_desc = acpi_ut_create_package_object(1); | |
672 | if (!pkg_obj_desc) { | |
673 | return (AE_NO_MEMORY); | |
674 | } | |
675 | ||
6a99b1c9 BM |
676 | pkg_obj_desc->package.elements[0] = original_object; |
677 | ||
678 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, | |
679 | "%s: Wrapped %s with expected Package object\n", | |
680 | data->pathname, | |
681 | acpi_ut_get_object_type_name(original_object))); | |
e5f69d6e BM |
682 | |
683 | /* Return the new object in the object pointer */ | |
684 | ||
685 | *obj_desc_ptr = pkg_obj_desc; | |
6a99b1c9 | 686 | data->flags |= ACPI_OBJECT_REPAIRED | ACPI_OBJECT_WRAPPED; |
e5f69d6e BM |
687 | return (AE_OK); |
688 | } |