Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6595 | serge | 1 | /****************************************************************************** |
2 | * |
||
3 | * Module Name: nsrepair2 - Repair for objects returned by specific |
||
4 | * predefined methods |
||
5 | * |
||
6 | *****************************************************************************/ |
||
7 | |||
8 | /* |
||
9 | * Copyright (C) 2000 - 2015, Intel Corp. |
||
10 | * All rights reserved. |
||
11 | * |
||
12 | * Redistribution and use in source and binary forms, with or without |
||
13 | * modification, are permitted provided that the following conditions |
||
14 | * are met: |
||
15 | * 1. Redistributions of source code must retain the above copyright |
||
16 | * notice, this list of conditions, and the following disclaimer, |
||
17 | * without modification. |
||
18 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer |
||
19 | * substantially similar to the "NO WARRANTY" disclaimer below |
||
20 | * ("Disclaimer") and any redistribution must be conditioned upon |
||
21 | * including a substantially similar Disclaimer requirement for further |
||
22 | * binary redistribution. |
||
23 | * 3. Neither the names of the above-listed copyright holders nor the names |
||
24 | * of any contributors may be used to endorse or promote products derived |
||
25 | * from this software without specific prior written permission. |
||
26 | * |
||
27 | * Alternatively, this software may be distributed under the terms of the |
||
28 | * GNU General Public License ("GPL") version 2 as published by the Free |
||
29 | * Software Foundation. |
||
30 | * |
||
31 | * NO WARRANTY |
||
32 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||
33 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||
34 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
||
35 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||
36 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||
37 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||
38 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||
39 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||
40 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
||
41 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||
42 | * POSSIBILITY OF SUCH DAMAGES. |
||
43 | */ |
||
44 | |||
45 | #include |
||
46 | #include "accommon.h" |
||
47 | #include "acnamesp.h" |
||
48 | |||
49 | #define _COMPONENT ACPI_NAMESPACE |
||
50 | ACPI_MODULE_NAME("nsrepair2") |
||
51 | |||
52 | /* |
||
53 | * Information structure and handler for ACPI predefined names that can |
||
54 | * be repaired on a per-name basis. |
||
55 | */ |
||
56 | typedef |
||
57 | acpi_status(*acpi_repair_function) (struct acpi_evaluate_info * info, |
||
58 | union acpi_operand_object |
||
59 | **return_object_ptr); |
||
60 | |||
61 | typedef struct acpi_repair_info { |
||
62 | char name[ACPI_NAME_SIZE]; |
||
63 | acpi_repair_function repair_function; |
||
64 | |||
65 | } acpi_repair_info; |
||
66 | |||
67 | /* Local prototypes */ |
||
68 | |||
69 | static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct |
||
70 | acpi_namespace_node |
||
71 | *node); |
||
72 | |||
73 | static acpi_status |
||
74 | acpi_ns_repair_ALR(struct acpi_evaluate_info *info, |
||
75 | union acpi_operand_object **return_object_ptr); |
||
76 | |||
77 | static acpi_status |
||
78 | acpi_ns_repair_CID(struct acpi_evaluate_info *info, |
||
79 | union acpi_operand_object **return_object_ptr); |
||
80 | |||
81 | static acpi_status |
||
82 | acpi_ns_repair_CST(struct acpi_evaluate_info *info, |
||
83 | union acpi_operand_object **return_object_ptr); |
||
84 | |||
85 | static acpi_status |
||
86 | acpi_ns_repair_FDE(struct acpi_evaluate_info *info, |
||
87 | union acpi_operand_object **return_object_ptr); |
||
88 | |||
89 | static acpi_status |
||
90 | acpi_ns_repair_HID(struct acpi_evaluate_info *info, |
||
91 | union acpi_operand_object **return_object_ptr); |
||
92 | |||
93 | static acpi_status |
||
94 | acpi_ns_repair_PRT(struct acpi_evaluate_info *info, |
||
95 | union acpi_operand_object **return_object_ptr); |
||
96 | |||
97 | static acpi_status |
||
98 | acpi_ns_repair_PSS(struct acpi_evaluate_info *info, |
||
99 | union acpi_operand_object **return_object_ptr); |
||
100 | |||
101 | static acpi_status |
||
102 | acpi_ns_repair_TSS(struct acpi_evaluate_info *info, |
||
103 | union acpi_operand_object **return_object_ptr); |
||
104 | |||
105 | static acpi_status |
||
106 | acpi_ns_check_sorted_list(struct acpi_evaluate_info *info, |
||
107 | union acpi_operand_object *return_object, |
||
108 | u32 start_index, |
||
109 | u32 expected_count, |
||
110 | u32 sort_index, |
||
111 | u8 sort_direction, char *sort_key_name); |
||
112 | |||
113 | /* Values for sort_direction above */ |
||
114 | |||
115 | #define ACPI_SORT_ASCENDING 0 |
||
116 | #define ACPI_SORT_DESCENDING 1 |
||
117 | |||
118 | static void |
||
119 | acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index); |
||
120 | |||
121 | static void |
||
122 | acpi_ns_sort_list(union acpi_operand_object **elements, |
||
123 | u32 count, u32 index, u8 sort_direction); |
||
124 | |||
125 | /* |
||
126 | * This table contains the names of the predefined methods for which we can |
||
127 | * perform more complex repairs. |
||
128 | * |
||
129 | * As necessary: |
||
130 | * |
||
131 | * _ALR: Sort the list ascending by ambient_illuminance |
||
132 | * _CID: Strings: uppercase all, remove any leading asterisk |
||
133 | * _CST: Sort the list ascending by C state type |
||
134 | * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs |
||
135 | * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs |
||
136 | * _HID: Strings: uppercase all, remove any leading asterisk |
||
137 | * _PRT: Fix reversed source_name and source_index |
||
138 | * _PSS: Sort the list descending by Power |
||
139 | * _TSS: Sort the list descending by Power |
||
140 | * |
||
141 | * Names that must be packages, but cannot be sorted: |
||
142 | * |
||
143 | * _BCL: Values are tied to the Package index where they appear, and cannot |
||
144 | * be moved or sorted. These index values are used for _BQC and _BCM. |
||
145 | * However, we can fix the case where a buffer is returned, by converting |
||
146 | * it to a Package of integers. |
||
147 | */ |
||
148 | static const struct acpi_repair_info acpi_ns_repairable_names[] = { |
||
149 | {"_ALR", acpi_ns_repair_ALR}, |
||
150 | {"_CID", acpi_ns_repair_CID}, |
||
151 | {"_CST", acpi_ns_repair_CST}, |
||
152 | {"_FDE", acpi_ns_repair_FDE}, |
||
153 | {"_GTM", acpi_ns_repair_FDE}, /* _GTM has same repair as _FDE */ |
||
154 | {"_HID", acpi_ns_repair_HID}, |
||
155 | {"_PRT", acpi_ns_repair_PRT}, |
||
156 | {"_PSS", acpi_ns_repair_PSS}, |
||
157 | {"_TSS", acpi_ns_repair_TSS}, |
||
158 | {{0, 0, 0, 0}, NULL} /* Table terminator */ |
||
159 | }; |
||
160 | |||
161 | #define ACPI_FDE_FIELD_COUNT 5 |
||
162 | #define ACPI_FDE_BYTE_BUFFER_SIZE 5 |
||
163 | #define ACPI_FDE_DWORD_BUFFER_SIZE (ACPI_FDE_FIELD_COUNT * sizeof (u32)) |
||
164 | |||
165 | /****************************************************************************** |
||
166 | * |
||
167 | * FUNCTION: acpi_ns_complex_repairs |
||
168 | * |
||
169 | * PARAMETERS: info - Method execution information block |
||
170 | * node - Namespace node for the method/object |
||
171 | * validate_status - Original status of earlier validation |
||
172 | * return_object_ptr - Pointer to the object returned from the |
||
173 | * evaluation of a method or object |
||
174 | * |
||
175 | * RETURN: Status. AE_OK if repair was successful. If name is not |
||
176 | * matched, validate_status is returned. |
||
177 | * |
||
178 | * DESCRIPTION: Attempt to repair/convert a return object of a type that was |
||
179 | * not expected. |
||
180 | * |
||
181 | *****************************************************************************/ |
||
182 | |||
183 | acpi_status |
||
184 | acpi_ns_complex_repairs(struct acpi_evaluate_info *info, |
||
185 | struct acpi_namespace_node *node, |
||
186 | acpi_status validate_status, |
||
187 | union acpi_operand_object **return_object_ptr) |
||
188 | { |
||
189 | const struct acpi_repair_info *predefined; |
||
190 | acpi_status status; |
||
191 | |||
192 | /* Check if this name is in the list of repairable names */ |
||
193 | |||
194 | predefined = acpi_ns_match_complex_repair(node); |
||
195 | if (!predefined) { |
||
196 | return (validate_status); |
||
197 | } |
||
198 | |||
199 | status = predefined->repair_function(info, return_object_ptr); |
||
200 | return (status); |
||
201 | } |
||
202 | |||
203 | /****************************************************************************** |
||
204 | * |
||
205 | * FUNCTION: acpi_ns_match_complex_repair |
||
206 | * |
||
207 | * PARAMETERS: node - Namespace node for the method/object |
||
208 | * |
||
209 | * RETURN: Pointer to entry in repair table. NULL indicates not found. |
||
210 | * |
||
211 | * DESCRIPTION: Check an object name against the repairable object list. |
||
212 | * |
||
213 | *****************************************************************************/ |
||
214 | |||
215 | static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct |
||
216 | acpi_namespace_node |
||
217 | *node) |
||
218 | { |
||
219 | const struct acpi_repair_info *this_name; |
||
220 | |||
221 | /* Search info table for a repairable predefined method/object name */ |
||
222 | |||
223 | this_name = acpi_ns_repairable_names; |
||
224 | while (this_name->repair_function) { |
||
225 | if (ACPI_COMPARE_NAME(node->name.ascii, this_name->name)) { |
||
226 | return (this_name); |
||
227 | } |
||
228 | this_name++; |
||
229 | } |
||
230 | |||
231 | return (NULL); /* Not found */ |
||
232 | } |
||
233 | |||
234 | /****************************************************************************** |
||
235 | * |
||
236 | * FUNCTION: acpi_ns_repair_ALR |
||
237 | * |
||
238 | * PARAMETERS: info - Method execution information block |
||
239 | * return_object_ptr - Pointer to the object returned from the |
||
240 | * evaluation of a method or object |
||
241 | * |
||
242 | * RETURN: Status. AE_OK if object is OK or was repaired successfully |
||
243 | * |
||
244 | * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list |
||
245 | * ascending by the ambient illuminance values. |
||
246 | * |
||
247 | *****************************************************************************/ |
||
248 | |||
249 | static acpi_status |
||
250 | acpi_ns_repair_ALR(struct acpi_evaluate_info *info, |
||
251 | union acpi_operand_object **return_object_ptr) |
||
252 | { |
||
253 | union acpi_operand_object *return_object = *return_object_ptr; |
||
254 | acpi_status status; |
||
255 | |||
256 | status = acpi_ns_check_sorted_list(info, return_object, 0, 2, 1, |
||
257 | ACPI_SORT_ASCENDING, |
||
258 | "AmbientIlluminance"); |
||
259 | |||
260 | return (status); |
||
261 | } |
||
262 | |||
263 | /****************************************************************************** |
||
264 | * |
||
265 | * FUNCTION: acpi_ns_repair_FDE |
||
266 | * |
||
267 | * PARAMETERS: info - Method execution information block |
||
268 | * return_object_ptr - Pointer to the object returned from the |
||
269 | * evaluation of a method or object |
||
270 | * |
||
271 | * RETURN: Status. AE_OK if object is OK or was repaired successfully |
||
272 | * |
||
273 | * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return |
||
274 | * value is a Buffer of 5 DWORDs. This function repairs a common |
||
275 | * problem where the return value is a Buffer of BYTEs, not |
||
276 | * DWORDs. |
||
277 | * |
||
278 | *****************************************************************************/ |
||
279 | |||
280 | static acpi_status |
||
281 | acpi_ns_repair_FDE(struct acpi_evaluate_info *info, |
||
282 | union acpi_operand_object **return_object_ptr) |
||
283 | { |
||
284 | union acpi_operand_object *return_object = *return_object_ptr; |
||
285 | union acpi_operand_object *buffer_object; |
||
286 | u8 *byte_buffer; |
||
287 | u32 *dword_buffer; |
||
288 | u32 i; |
||
289 | |||
290 | ACPI_FUNCTION_NAME(ns_repair_FDE); |
||
291 | |||
292 | switch (return_object->common.type) { |
||
293 | case ACPI_TYPE_BUFFER: |
||
294 | |||
295 | /* This is the expected type. Length should be (at least) 5 DWORDs */ |
||
296 | |||
297 | if (return_object->buffer.length >= ACPI_FDE_DWORD_BUFFER_SIZE) { |
||
298 | return (AE_OK); |
||
299 | } |
||
300 | |||
301 | /* We can only repair if we have exactly 5 BYTEs */ |
||
302 | |||
303 | if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) { |
||
304 | ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
||
305 | info->node_flags, |
||
306 | "Incorrect return buffer length %u, expected %u", |
||
307 | return_object->buffer.length, |
||
308 | ACPI_FDE_DWORD_BUFFER_SIZE)); |
||
309 | |||
310 | return (AE_AML_OPERAND_TYPE); |
||
311 | } |
||
312 | |||
313 | /* Create the new (larger) buffer object */ |
||
314 | |||
315 | buffer_object = |
||
316 | acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE); |
||
317 | if (!buffer_object) { |
||
318 | return (AE_NO_MEMORY); |
||
319 | } |
||
320 | |||
321 | /* Expand each byte to a DWORD */ |
||
322 | |||
323 | byte_buffer = return_object->buffer.pointer; |
||
324 | dword_buffer = |
||
325 | ACPI_CAST_PTR(u32, buffer_object->buffer.pointer); |
||
326 | |||
327 | for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) { |
||
328 | *dword_buffer = (u32) *byte_buffer; |
||
329 | dword_buffer++; |
||
330 | byte_buffer++; |
||
331 | } |
||
332 | |||
333 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
||
334 | "%s Expanded Byte Buffer to expected DWord Buffer\n", |
||
335 | info->full_pathname)); |
||
336 | break; |
||
337 | |||
338 | default: |
||
339 | |||
340 | return (AE_AML_OPERAND_TYPE); |
||
341 | } |
||
342 | |||
343 | /* Delete the original return object, return the new buffer object */ |
||
344 | |||
345 | acpi_ut_remove_reference(return_object); |
||
346 | *return_object_ptr = buffer_object; |
||
347 | |||
348 | info->return_flags |= ACPI_OBJECT_REPAIRED; |
||
349 | return (AE_OK); |
||
350 | } |
||
351 | |||
352 | /****************************************************************************** |
||
353 | * |
||
354 | * FUNCTION: acpi_ns_repair_CID |
||
355 | * |
||
356 | * PARAMETERS: info - Method execution information block |
||
357 | * return_object_ptr - Pointer to the object returned from the |
||
358 | * evaluation of a method or object |
||
359 | * |
||
360 | * RETURN: Status. AE_OK if object is OK or was repaired successfully |
||
361 | * |
||
362 | * DESCRIPTION: Repair for the _CID object. If a string, ensure that all |
||
363 | * letters are uppercase and that there is no leading asterisk. |
||
364 | * If a Package, ensure same for all string elements. |
||
365 | * |
||
366 | *****************************************************************************/ |
||
367 | |||
368 | static acpi_status |
||
369 | acpi_ns_repair_CID(struct acpi_evaluate_info *info, |
||
370 | union acpi_operand_object **return_object_ptr) |
||
371 | { |
||
372 | acpi_status status; |
||
373 | union acpi_operand_object *return_object = *return_object_ptr; |
||
374 | union acpi_operand_object **element_ptr; |
||
375 | union acpi_operand_object *original_element; |
||
376 | u16 original_ref_count; |
||
377 | u32 i; |
||
378 | |||
379 | /* Check for _CID as a simple string */ |
||
380 | |||
381 | if (return_object->common.type == ACPI_TYPE_STRING) { |
||
382 | status = acpi_ns_repair_HID(info, return_object_ptr); |
||
383 | return (status); |
||
384 | } |
||
385 | |||
386 | /* Exit if not a Package */ |
||
387 | |||
388 | if (return_object->common.type != ACPI_TYPE_PACKAGE) { |
||
389 | return (AE_OK); |
||
390 | } |
||
391 | |||
392 | /* Examine each element of the _CID package */ |
||
393 | |||
394 | element_ptr = return_object->package.elements; |
||
395 | for (i = 0; i < return_object->package.count; i++) { |
||
396 | original_element = *element_ptr; |
||
397 | original_ref_count = original_element->common.reference_count; |
||
398 | |||
399 | status = acpi_ns_repair_HID(info, element_ptr); |
||
400 | if (ACPI_FAILURE(status)) { |
||
401 | return (status); |
||
402 | } |
||
403 | |||
404 | /* Take care with reference counts */ |
||
405 | |||
406 | if (original_element != *element_ptr) { |
||
407 | |||
408 | /* Element was replaced */ |
||
409 | |||
410 | (*element_ptr)->common.reference_count = |
||
411 | original_ref_count; |
||
412 | |||
413 | acpi_ut_remove_reference(original_element); |
||
414 | } |
||
415 | |||
416 | element_ptr++; |
||
417 | } |
||
418 | |||
419 | return (AE_OK); |
||
420 | } |
||
421 | |||
422 | /****************************************************************************** |
||
423 | * |
||
424 | * FUNCTION: acpi_ns_repair_CST |
||
425 | * |
||
426 | * PARAMETERS: info - Method execution information block |
||
427 | * return_object_ptr - Pointer to the object returned from the |
||
428 | * evaluation of a method or object |
||
429 | * |
||
430 | * RETURN: Status. AE_OK if object is OK or was repaired successfully |
||
431 | * |
||
432 | * DESCRIPTION: Repair for the _CST object: |
||
433 | * 1. Sort the list ascending by C state type |
||
434 | * 2. Ensure type cannot be zero |
||
435 | * 3. A subpackage count of zero means _CST is meaningless |
||
436 | * 4. Count must match the number of C state subpackages |
||
437 | * |
||
438 | *****************************************************************************/ |
||
439 | |||
440 | static acpi_status |
||
441 | acpi_ns_repair_CST(struct acpi_evaluate_info *info, |
||
442 | union acpi_operand_object **return_object_ptr) |
||
443 | { |
||
444 | union acpi_operand_object *return_object = *return_object_ptr; |
||
445 | union acpi_operand_object **outer_elements; |
||
446 | u32 outer_element_count; |
||
447 | union acpi_operand_object *obj_desc; |
||
448 | acpi_status status; |
||
449 | u8 removing; |
||
450 | u32 i; |
||
451 | |||
452 | ACPI_FUNCTION_NAME(ns_repair_CST); |
||
453 | |||
454 | /* |
||
455 | * Check if the C-state type values are proportional. |
||
456 | */ |
||
457 | outer_element_count = return_object->package.count - 1; |
||
458 | i = 0; |
||
459 | while (i < outer_element_count) { |
||
460 | outer_elements = &return_object->package.elements[i + 1]; |
||
461 | removing = FALSE; |
||
462 | |||
463 | if ((*outer_elements)->package.count == 0) { |
||
464 | ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
||
465 | info->node_flags, |
||
466 | "SubPackage[%u] - removing entry due to zero count", |
||
467 | i)); |
||
468 | removing = TRUE; |
||
469 | goto remove_element; |
||
470 | } |
||
471 | |||
472 | obj_desc = (*outer_elements)->package.elements[1]; /* Index1 = Type */ |
||
473 | if ((u32)obj_desc->integer.value == 0) { |
||
474 | ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
||
475 | info->node_flags, |
||
476 | "SubPackage[%u] - removing entry due to invalid Type(0)", |
||
477 | i)); |
||
478 | removing = TRUE; |
||
479 | } |
||
480 | |||
481 | remove_element: |
||
482 | if (removing) { |
||
483 | acpi_ns_remove_element(return_object, i + 1); |
||
484 | outer_element_count--; |
||
485 | } else { |
||
486 | i++; |
||
487 | } |
||
488 | } |
||
489 | |||
490 | /* Update top-level package count, Type "Integer" checked elsewhere */ |
||
491 | |||
492 | obj_desc = return_object->package.elements[0]; |
||
493 | obj_desc->integer.value = outer_element_count; |
||
494 | |||
495 | /* |
||
496 | * Entries (subpackages) in the _CST Package must be sorted by the |
||
497 | * C-state type, in ascending order. |
||
498 | */ |
||
499 | status = acpi_ns_check_sorted_list(info, return_object, 1, 4, 1, |
||
500 | ACPI_SORT_ASCENDING, "C-State Type"); |
||
501 | if (ACPI_FAILURE(status)) { |
||
502 | return (status); |
||
503 | } |
||
504 | |||
505 | return (AE_OK); |
||
506 | } |
||
507 | |||
508 | /****************************************************************************** |
||
509 | * |
||
510 | * FUNCTION: acpi_ns_repair_HID |
||
511 | * |
||
512 | * PARAMETERS: info - Method execution information block |
||
513 | * return_object_ptr - Pointer to the object returned from the |
||
514 | * evaluation of a method or object |
||
515 | * |
||
516 | * RETURN: Status. AE_OK if object is OK or was repaired successfully |
||
517 | * |
||
518 | * DESCRIPTION: Repair for the _HID object. If a string, ensure that all |
||
519 | * letters are uppercase and that there is no leading asterisk. |
||
520 | * |
||
521 | *****************************************************************************/ |
||
522 | |||
523 | static acpi_status |
||
524 | acpi_ns_repair_HID(struct acpi_evaluate_info *info, |
||
525 | union acpi_operand_object **return_object_ptr) |
||
526 | { |
||
527 | union acpi_operand_object *return_object = *return_object_ptr; |
||
528 | union acpi_operand_object *new_string; |
||
529 | char *source; |
||
530 | char *dest; |
||
531 | |||
532 | ACPI_FUNCTION_NAME(ns_repair_HID); |
||
533 | |||
534 | /* We only care about string _HID objects (not integers) */ |
||
535 | |||
536 | if (return_object->common.type != ACPI_TYPE_STRING) { |
||
537 | return (AE_OK); |
||
538 | } |
||
539 | |||
540 | if (return_object->string.length == 0) { |
||
541 | ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
||
542 | info->node_flags, |
||
543 | "Invalid zero-length _HID or _CID string")); |
||
544 | |||
545 | /* Return AE_OK anyway, let driver handle it */ |
||
546 | |||
547 | info->return_flags |= ACPI_OBJECT_REPAIRED; |
||
548 | return (AE_OK); |
||
549 | } |
||
550 | |||
551 | /* It is simplest to always create a new string object */ |
||
552 | |||
553 | new_string = acpi_ut_create_string_object(return_object->string.length); |
||
554 | if (!new_string) { |
||
555 | return (AE_NO_MEMORY); |
||
556 | } |
||
557 | |||
558 | /* |
||
559 | * Remove a leading asterisk if present. For some unknown reason, there |
||
560 | * are many machines in the field that contains IDs like this. |
||
561 | * |
||
562 | * Examples: "*PNP0C03", "*ACPI0003" |
||
563 | */ |
||
564 | source = return_object->string.pointer; |
||
565 | if (*source == '*') { |
||
566 | source++; |
||
567 | new_string->string.length--; |
||
568 | |||
569 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
||
570 | "%s: Removed invalid leading asterisk\n", |
||
571 | info->full_pathname)); |
||
572 | } |
||
573 | |||
574 | /* |
||
575 | * Copy and uppercase the string. From the ACPI 5.0 specification: |
||
576 | * |
||
577 | * A valid PNP ID must be of the form "AAA####" where A is an uppercase |
||
578 | * letter and # is a hex digit. A valid ACPI ID must be of the form |
||
579 | * "NNNN####" where N is an uppercase letter or decimal digit, and |
||
580 | * # is a hex digit. |
||
581 | */ |
||
582 | for (dest = new_string->string.pointer; *source; dest++, source++) { |
||
583 | *dest = (char)toupper((int)*source); |
||
584 | } |
||
585 | |||
586 | acpi_ut_remove_reference(return_object); |
||
587 | *return_object_ptr = new_string; |
||
588 | return (AE_OK); |
||
589 | } |
||
590 | |||
591 | /****************************************************************************** |
||
592 | * |
||
593 | * FUNCTION: acpi_ns_repair_PRT |
||
594 | * |
||
595 | * PARAMETERS: info - Method execution information block |
||
596 | * return_object_ptr - Pointer to the object returned from the |
||
597 | * evaluation of a method or object |
||
598 | * |
||
599 | * RETURN: Status. AE_OK if object is OK or was repaired successfully |
||
600 | * |
||
601 | * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed |
||
602 | * source_name and source_index field, a common BIOS bug. |
||
603 | * |
||
604 | *****************************************************************************/ |
||
605 | |||
606 | static acpi_status |
||
607 | acpi_ns_repair_PRT(struct acpi_evaluate_info *info, |
||
608 | union acpi_operand_object **return_object_ptr) |
||
609 | { |
||
610 | union acpi_operand_object *package_object = *return_object_ptr; |
||
611 | union acpi_operand_object **top_object_list; |
||
612 | union acpi_operand_object **sub_object_list; |
||
613 | union acpi_operand_object *obj_desc; |
||
614 | union acpi_operand_object *sub_package; |
||
615 | u32 element_count; |
||
616 | u32 index; |
||
617 | |||
618 | /* Each element in the _PRT package is a subpackage */ |
||
619 | |||
620 | top_object_list = package_object->package.elements; |
||
621 | element_count = package_object->package.count; |
||
622 | |||
623 | /* Examine each subpackage */ |
||
624 | |||
625 | for (index = 0; index < element_count; index++, top_object_list++) { |
||
626 | sub_package = *top_object_list; |
||
627 | sub_object_list = sub_package->package.elements; |
||
628 | |||
629 | /* Check for minimum required element count */ |
||
630 | |||
631 | if (sub_package->package.count < 4) { |
||
632 | continue; |
||
633 | } |
||
634 | |||
635 | /* |
||
636 | * If the BIOS has erroneously reversed the _PRT source_name (index 2) |
||
637 | * and the source_index (index 3), fix it. _PRT is important enough to |
||
638 | * workaround this BIOS error. This also provides compatibility with |
||
639 | * other ACPI implementations. |
||
640 | */ |
||
641 | obj_desc = sub_object_list[3]; |
||
642 | if (!obj_desc || (obj_desc->common.type != ACPI_TYPE_INTEGER)) { |
||
643 | sub_object_list[3] = sub_object_list[2]; |
||
644 | sub_object_list[2] = obj_desc; |
||
645 | info->return_flags |= ACPI_OBJECT_REPAIRED; |
||
646 | |||
647 | ACPI_WARN_PREDEFINED((AE_INFO, |
||
648 | info->full_pathname, |
||
649 | info->node_flags, |
||
650 | "PRT[%X]: Fixed reversed SourceName and SourceIndex", |
||
651 | index)); |
||
652 | } |
||
653 | } |
||
654 | |||
655 | return (AE_OK); |
||
656 | } |
||
657 | |||
658 | /****************************************************************************** |
||
659 | * |
||
660 | * FUNCTION: acpi_ns_repair_PSS |
||
661 | * |
||
662 | * PARAMETERS: info - Method execution information block |
||
663 | * return_object_ptr - Pointer to the object returned from the |
||
664 | * evaluation of a method or object |
||
665 | * |
||
666 | * RETURN: Status. AE_OK if object is OK or was repaired successfully |
||
667 | * |
||
668 | * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list |
||
669 | * by the CPU frequencies. Check that the power dissipation values |
||
670 | * are all proportional to CPU frequency (i.e., sorting by |
||
671 | * frequency should be the same as sorting by power.) |
||
672 | * |
||
673 | *****************************************************************************/ |
||
674 | |||
675 | static acpi_status |
||
676 | acpi_ns_repair_PSS(struct acpi_evaluate_info *info, |
||
677 | union acpi_operand_object **return_object_ptr) |
||
678 | { |
||
679 | union acpi_operand_object *return_object = *return_object_ptr; |
||
680 | union acpi_operand_object **outer_elements; |
||
681 | u32 outer_element_count; |
||
682 | union acpi_operand_object **elements; |
||
683 | union acpi_operand_object *obj_desc; |
||
684 | u32 previous_value; |
||
685 | acpi_status status; |
||
686 | u32 i; |
||
687 | |||
688 | /* |
||
689 | * Entries (subpackages) in the _PSS Package must be sorted by power |
||
690 | * dissipation, in descending order. If it appears that the list is |
||
691 | * incorrectly sorted, sort it. We sort by cpu_frequency, since this |
||
692 | * should be proportional to the power. |
||
693 | */ |
||
694 | status = acpi_ns_check_sorted_list(info, return_object, 0, 6, 0, |
||
695 | ACPI_SORT_DESCENDING, |
||
696 | "CpuFrequency"); |
||
697 | if (ACPI_FAILURE(status)) { |
||
698 | return (status); |
||
699 | } |
||
700 | |||
701 | /* |
||
702 | * We now know the list is correctly sorted by CPU frequency. Check if |
||
703 | * the power dissipation values are proportional. |
||
704 | */ |
||
705 | previous_value = ACPI_UINT32_MAX; |
||
706 | outer_elements = return_object->package.elements; |
||
707 | outer_element_count = return_object->package.count; |
||
708 | |||
709 | for (i = 0; i < outer_element_count; i++) { |
||
710 | elements = (*outer_elements)->package.elements; |
||
711 | obj_desc = elements[1]; /* Index1 = power_dissipation */ |
||
712 | |||
713 | if ((u32) obj_desc->integer.value > previous_value) { |
||
714 | ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, |
||
715 | info->node_flags, |
||
716 | "SubPackage[%u,%u] - suspicious power dissipation values", |
||
717 | i - 1, i)); |
||
718 | } |
||
719 | |||
720 | previous_value = (u32) obj_desc->integer.value; |
||
721 | outer_elements++; |
||
722 | } |
||
723 | |||
724 | return (AE_OK); |
||
725 | } |
||
726 | |||
727 | /****************************************************************************** |
||
728 | * |
||
729 | * FUNCTION: acpi_ns_repair_TSS |
||
730 | * |
||
731 | * PARAMETERS: info - Method execution information block |
||
732 | * return_object_ptr - Pointer to the object returned from the |
||
733 | * evaluation of a method or object |
||
734 | * |
||
735 | * RETURN: Status. AE_OK if object is OK or was repaired successfully |
||
736 | * |
||
737 | * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list |
||
738 | * descending by the power dissipation values. |
||
739 | * |
||
740 | *****************************************************************************/ |
||
741 | |||
742 | static acpi_status |
||
743 | acpi_ns_repair_TSS(struct acpi_evaluate_info *info, |
||
744 | union acpi_operand_object **return_object_ptr) |
||
745 | { |
||
746 | union acpi_operand_object *return_object = *return_object_ptr; |
||
747 | acpi_status status; |
||
748 | struct acpi_namespace_node *node; |
||
749 | |||
750 | /* |
||
751 | * We can only sort the _TSS return package if there is no _PSS in the |
||
752 | * same scope. This is because if _PSS is present, the ACPI specification |
||
753 | * dictates that the _TSS Power Dissipation field is to be ignored, and |
||
754 | * therefore some BIOSs leave garbage values in the _TSS Power field(s). |
||
755 | * In this case, it is best to just return the _TSS package as-is. |
||
756 | * (May, 2011) |
||
757 | */ |
||
758 | status = acpi_ns_get_node(info->node, "^_PSS", |
||
759 | ACPI_NS_NO_UPSEARCH, &node); |
||
760 | if (ACPI_SUCCESS(status)) { |
||
761 | return (AE_OK); |
||
762 | } |
||
763 | |||
764 | status = acpi_ns_check_sorted_list(info, return_object, 0, 5, 1, |
||
765 | ACPI_SORT_DESCENDING, |
||
766 | "PowerDissipation"); |
||
767 | |||
768 | return (status); |
||
769 | } |
||
770 | |||
771 | /****************************************************************************** |
||
772 | * |
||
773 | * FUNCTION: acpi_ns_check_sorted_list |
||
774 | * |
||
775 | * PARAMETERS: info - Method execution information block |
||
776 | * return_object - Pointer to the top-level returned object |
||
777 | * start_index - Index of the first subpackage |
||
778 | * expected_count - Minimum length of each subpackage |
||
779 | * sort_index - Subpackage entry to sort on |
||
780 | * sort_direction - Ascending or descending |
||
781 | * sort_key_name - Name of the sort_index field |
||
782 | * |
||
783 | * RETURN: Status. AE_OK if the list is valid and is sorted correctly or |
||
784 | * has been repaired by sorting the list. |
||
785 | * |
||
786 | * DESCRIPTION: Check if the package list is valid and sorted correctly by the |
||
787 | * sort_index. If not, then sort the list. |
||
788 | * |
||
789 | *****************************************************************************/ |
||
790 | |||
791 | static acpi_status |
||
792 | acpi_ns_check_sorted_list(struct acpi_evaluate_info *info, |
||
793 | union acpi_operand_object *return_object, |
||
794 | u32 start_index, |
||
795 | u32 expected_count, |
||
796 | u32 sort_index, |
||
797 | u8 sort_direction, char *sort_key_name) |
||
798 | { |
||
799 | u32 outer_element_count; |
||
800 | union acpi_operand_object **outer_elements; |
||
801 | union acpi_operand_object **elements; |
||
802 | union acpi_operand_object *obj_desc; |
||
803 | u32 i; |
||
804 | u32 previous_value; |
||
805 | |||
806 | ACPI_FUNCTION_NAME(ns_check_sorted_list); |
||
807 | |||
808 | /* The top-level object must be a package */ |
||
809 | |||
810 | if (return_object->common.type != ACPI_TYPE_PACKAGE) { |
||
811 | return (AE_AML_OPERAND_TYPE); |
||
812 | } |
||
813 | |||
814 | /* |
||
815 | * NOTE: assumes list of subpackages contains no NULL elements. |
||
816 | * Any NULL elements should have been removed by earlier call |
||
817 | * to acpi_ns_remove_null_elements. |
||
818 | */ |
||
819 | outer_element_count = return_object->package.count; |
||
820 | if (!outer_element_count || start_index >= outer_element_count) { |
||
821 | return (AE_AML_PACKAGE_LIMIT); |
||
822 | } |
||
823 | |||
824 | outer_elements = &return_object->package.elements[start_index]; |
||
825 | outer_element_count -= start_index; |
||
826 | |||
827 | previous_value = 0; |
||
828 | if (sort_direction == ACPI_SORT_DESCENDING) { |
||
829 | previous_value = ACPI_UINT32_MAX; |
||
830 | } |
||
831 | |||
832 | /* Examine each subpackage */ |
||
833 | |||
834 | for (i = 0; i < outer_element_count; i++) { |
||
835 | |||
836 | /* Each element of the top-level package must also be a package */ |
||
837 | |||
838 | if ((*outer_elements)->common.type != ACPI_TYPE_PACKAGE) { |
||
839 | return (AE_AML_OPERAND_TYPE); |
||
840 | } |
||
841 | |||
842 | /* Each subpackage must have the minimum length */ |
||
843 | |||
844 | if ((*outer_elements)->package.count < expected_count) { |
||
845 | return (AE_AML_PACKAGE_LIMIT); |
||
846 | } |
||
847 | |||
848 | elements = (*outer_elements)->package.elements; |
||
849 | obj_desc = elements[sort_index]; |
||
850 | |||
851 | if (obj_desc->common.type != ACPI_TYPE_INTEGER) { |
||
852 | return (AE_AML_OPERAND_TYPE); |
||
853 | } |
||
854 | |||
855 | /* |
||
856 | * The list must be sorted in the specified order. If we detect a |
||
857 | * discrepancy, sort the entire list. |
||
858 | */ |
||
859 | if (((sort_direction == ACPI_SORT_ASCENDING) && |
||
860 | (obj_desc->integer.value < previous_value)) || |
||
861 | ((sort_direction == ACPI_SORT_DESCENDING) && |
||
862 | (obj_desc->integer.value > previous_value))) { |
||
863 | acpi_ns_sort_list(&return_object->package. |
||
864 | elements[start_index], |
||
865 | outer_element_count, sort_index, |
||
866 | sort_direction); |
||
867 | |||
868 | info->return_flags |= ACPI_OBJECT_REPAIRED; |
||
869 | |||
870 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
||
871 | "%s: Repaired unsorted list - now sorted by %s\n", |
||
872 | info->full_pathname, sort_key_name)); |
||
873 | return (AE_OK); |
||
874 | } |
||
875 | |||
876 | previous_value = (u32) obj_desc->integer.value; |
||
877 | outer_elements++; |
||
878 | } |
||
879 | |||
880 | return (AE_OK); |
||
881 | } |
||
882 | |||
883 | /****************************************************************************** |
||
884 | * |
||
885 | * FUNCTION: acpi_ns_sort_list |
||
886 | * |
||
887 | * PARAMETERS: elements - Package object element list |
||
888 | * count - Element count for above |
||
889 | * index - Sort by which package element |
||
890 | * sort_direction - Ascending or Descending sort |
||
891 | * |
||
892 | * RETURN: None |
||
893 | * |
||
894 | * DESCRIPTION: Sort the objects that are in a package element list. |
||
895 | * |
||
896 | * NOTE: Assumes that all NULL elements have been removed from the package, |
||
897 | * and that all elements have been verified to be of type Integer. |
||
898 | * |
||
899 | *****************************************************************************/ |
||
900 | |||
901 | static void |
||
902 | acpi_ns_sort_list(union acpi_operand_object **elements, |
||
903 | u32 count, u32 index, u8 sort_direction) |
||
904 | { |
||
905 | union acpi_operand_object *obj_desc1; |
||
906 | union acpi_operand_object *obj_desc2; |
||
907 | union acpi_operand_object *temp_obj; |
||
908 | u32 i; |
||
909 | u32 j; |
||
910 | |||
911 | /* Simple bubble sort */ |
||
912 | |||
913 | for (i = 1; i < count; i++) { |
||
914 | for (j = (count - 1); j >= i; j--) { |
||
915 | obj_desc1 = elements[j - 1]->package.elements[index]; |
||
916 | obj_desc2 = elements[j]->package.elements[index]; |
||
917 | |||
918 | if (((sort_direction == ACPI_SORT_ASCENDING) && |
||
919 | (obj_desc1->integer.value > |
||
920 | obj_desc2->integer.value)) |
||
921 | || ((sort_direction == ACPI_SORT_DESCENDING) |
||
922 | && (obj_desc1->integer.value < |
||
923 | obj_desc2->integer.value))) { |
||
924 | temp_obj = elements[j - 1]; |
||
925 | elements[j - 1] = elements[j]; |
||
926 | elements[j] = temp_obj; |
||
927 | } |
||
928 | } |
||
929 | } |
||
930 | } |
||
931 | |||
932 | /****************************************************************************** |
||
933 | * |
||
934 | * FUNCTION: acpi_ns_remove_element |
||
935 | * |
||
936 | * PARAMETERS: obj_desc - Package object element list |
||
937 | * index - Index of element to remove |
||
938 | * |
||
939 | * RETURN: None |
||
940 | * |
||
941 | * DESCRIPTION: Remove the requested element of a package and delete it. |
||
942 | * |
||
943 | *****************************************************************************/ |
||
944 | |||
945 | static void |
||
946 | acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index) |
||
947 | { |
||
948 | union acpi_operand_object **source; |
||
949 | union acpi_operand_object **dest; |
||
950 | u32 count; |
||
951 | u32 new_count; |
||
952 | u32 i; |
||
953 | |||
954 | ACPI_FUNCTION_NAME(ns_remove_element); |
||
955 | |||
956 | count = obj_desc->package.count; |
||
957 | new_count = count - 1; |
||
958 | |||
959 | source = obj_desc->package.elements; |
||
960 | dest = source; |
||
961 | |||
962 | /* Examine all elements of the package object, remove matched index */ |
||
963 | |||
964 | for (i = 0; i < count; i++) { |
||
965 | if (i == index) { |
||
966 | acpi_ut_remove_reference(*source); /* Remove one ref for being in pkg */ |
||
967 | acpi_ut_remove_reference(*source); |
||
968 | } else { |
||
969 | *dest = *source; |
||
970 | dest++; |
||
971 | } |
||
972 | source++; |
||
973 | } |
||
974 | |||
975 | /* NULL terminate list and update the package count */ |
||
976 | |||
977 | *dest = NULL; |
||
978 | obj_desc->package.count = new_count; |
||
979 | }> |