60b895b5dc629f875eb39dfbff208b020308d92a
[dragonfly.git] / sys / contrib / dev / acpica / source / components / namespace / nsrepair2.c
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 "acpi.h"
46 #include "accommon.h"
47 #include "acnamesp.h"
48
49 #define _COMPONENT          ACPI_NAMESPACE
50         ACPI_MODULE_NAME    ("nsrepair2")
51
52
53 /*
54  * Information structure and handler for ACPI predefined names that can
55  * be repaired on a per-name basis.
56  */
57 typedef
58 ACPI_STATUS (*ACPI_REPAIR_FUNCTION) (
59     ACPI_EVALUATE_INFO      *Info,
60     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
61
62 typedef struct acpi_repair_info
63 {
64     char                    Name[ACPI_NAME_SIZE];
65     ACPI_REPAIR_FUNCTION    RepairFunction;
66
67 } ACPI_REPAIR_INFO;
68
69
70 /* Local prototypes */
71
72 static const ACPI_REPAIR_INFO *
73 AcpiNsMatchComplexRepair (
74     ACPI_NAMESPACE_NODE     *Node);
75
76 static ACPI_STATUS
77 AcpiNsRepair_ALR (
78     ACPI_EVALUATE_INFO      *Info,
79     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
80
81 static ACPI_STATUS
82 AcpiNsRepair_CID (
83     ACPI_EVALUATE_INFO      *Info,
84     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
85
86 static ACPI_STATUS
87 AcpiNsRepair_CST (
88     ACPI_EVALUATE_INFO      *Info,
89     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
90
91 static ACPI_STATUS
92 AcpiNsRepair_FDE (
93     ACPI_EVALUATE_INFO      *Info,
94     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
95
96 static ACPI_STATUS
97 AcpiNsRepair_HID (
98     ACPI_EVALUATE_INFO      *Info,
99     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
100
101 static ACPI_STATUS
102 AcpiNsRepair_PRT (
103     ACPI_EVALUATE_INFO      *Info,
104     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
105
106 static ACPI_STATUS
107 AcpiNsRepair_PSS (
108     ACPI_EVALUATE_INFO      *Info,
109     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
110
111 static ACPI_STATUS
112 AcpiNsRepair_TSS (
113     ACPI_EVALUATE_INFO      *Info,
114     ACPI_OPERAND_OBJECT     **ReturnObjectPtr);
115
116 static ACPI_STATUS
117 AcpiNsCheckSortedList (
118     ACPI_EVALUATE_INFO      *Info,
119     ACPI_OPERAND_OBJECT     *ReturnObject,
120     UINT32                  StartIndex,
121     UINT32                  ExpectedCount,
122     UINT32                  SortIndex,
123     UINT8                   SortDirection,
124     char                    *SortKeyName);
125
126 /* Values for SortDirection above */
127
128 #define ACPI_SORT_ASCENDING     0
129 #define ACPI_SORT_DESCENDING    1
130
131 static void
132 AcpiNsRemoveElement (
133     ACPI_OPERAND_OBJECT     *ObjDesc,
134     UINT32                  Index);
135
136 static void
137 AcpiNsSortList (
138     ACPI_OPERAND_OBJECT     **Elements,
139     UINT32                  Count,
140     UINT32                  Index,
141     UINT8                   SortDirection);
142
143
144 /*
145  * This table contains the names of the predefined methods for which we can
146  * perform more complex repairs.
147  *
148  * As necessary:
149  *
150  * _ALR: Sort the list ascending by AmbientIlluminance
151  * _CID: Strings: uppercase all, remove any leading asterisk
152  * _CST: Sort the list ascending by C state type
153  * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
154  * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
155  * _HID: Strings: uppercase all, remove any leading asterisk
156  * _PRT: Fix reversed SourceName and SourceIndex
157  * _PSS: Sort the list descending by Power
158  * _TSS: Sort the list descending by Power
159  *
160  * Names that must be packages, but cannot be sorted:
161  *
162  * _BCL: Values are tied to the Package index where they appear, and cannot
163  * be moved or sorted. These index values are used for _BQC and _BCM.
164  * However, we can fix the case where a buffer is returned, by converting
165  * it to a Package of integers.
166  */
167 static const ACPI_REPAIR_INFO       AcpiNsRepairableNames[] =
168 {
169     {"_ALR", AcpiNsRepair_ALR},
170     {"_CID", AcpiNsRepair_CID},
171     {"_CST", AcpiNsRepair_CST},
172     {"_FDE", AcpiNsRepair_FDE},
173     {"_GTM", AcpiNsRepair_FDE},     /* _GTM has same repair as _FDE */
174     {"_HID", AcpiNsRepair_HID},
175     {"_PRT", AcpiNsRepair_PRT},
176     {"_PSS", AcpiNsRepair_PSS},
177     {"_TSS", AcpiNsRepair_TSS},
178     {{0,0,0,0}, NULL}               /* Table terminator */
179 };
180
181
182 #define ACPI_FDE_FIELD_COUNT        5
183 #define ACPI_FDE_BYTE_BUFFER_SIZE   5
184 #define ACPI_FDE_DWORD_BUFFER_SIZE  (ACPI_FDE_FIELD_COUNT * sizeof (UINT32))
185
186
187 /******************************************************************************
188  *
189  * FUNCTION:    AcpiNsComplexRepairs
190  *
191  * PARAMETERS:  Info                - Method execution information block
192  *              Node                - Namespace node for the method/object
193  *              ValidateStatus      - Original status of earlier validation
194  *              ReturnObjectPtr     - Pointer to the object returned from the
195  *                                    evaluation of a method or object
196  *
197  * RETURN:      Status. AE_OK if repair was successful. If name is not
198  *              matched, ValidateStatus is returned.
199  *
200  * DESCRIPTION: Attempt to repair/convert a return object of a type that was
201  *              not expected.
202  *
203  *****************************************************************************/
204
205 ACPI_STATUS
206 AcpiNsComplexRepairs (
207     ACPI_EVALUATE_INFO      *Info,
208     ACPI_NAMESPACE_NODE     *Node,
209     ACPI_STATUS             ValidateStatus,
210     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
211 {
212     const ACPI_REPAIR_INFO  *Predefined;
213     ACPI_STATUS             Status;
214
215
216     /* Check if this name is in the list of repairable names */
217
218     Predefined = AcpiNsMatchComplexRepair (Node);
219     if (!Predefined)
220     {
221         return (ValidateStatus);
222     }
223
224     Status = Predefined->RepairFunction (Info, ReturnObjectPtr);
225     return (Status);
226 }
227
228
229 /******************************************************************************
230  *
231  * FUNCTION:    AcpiNsMatchComplexRepair
232  *
233  * PARAMETERS:  Node                - Namespace node for the method/object
234  *
235  * RETURN:      Pointer to entry in repair table. NULL indicates not found.
236  *
237  * DESCRIPTION: Check an object name against the repairable object list.
238  *
239  *****************************************************************************/
240
241 static const ACPI_REPAIR_INFO *
242 AcpiNsMatchComplexRepair (
243     ACPI_NAMESPACE_NODE     *Node)
244 {
245     const ACPI_REPAIR_INFO  *ThisName;
246
247
248     /* Search info table for a repairable predefined method/object name */
249
250     ThisName = AcpiNsRepairableNames;
251     while (ThisName->RepairFunction)
252     {
253         if (ACPI_COMPARE_NAME (Node->Name.Ascii, ThisName->Name))
254         {
255             return (ThisName);
256         }
257         ThisName++;
258     }
259
260     return (NULL); /* Not found */
261 }
262
263
264 /******************************************************************************
265  *
266  * FUNCTION:    AcpiNsRepair_ALR
267  *
268  * PARAMETERS:  Info                - Method execution information block
269  *              ReturnObjectPtr     - Pointer to the object returned from the
270  *                                    evaluation of a method or object
271  *
272  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
273  *
274  * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list
275  *              ascending by the ambient illuminance values.
276  *
277  *****************************************************************************/
278
279 static ACPI_STATUS
280 AcpiNsRepair_ALR (
281     ACPI_EVALUATE_INFO      *Info,
282     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
283 {
284     ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
285     ACPI_STATUS             Status;
286
287
288     Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 2, 1,
289                 ACPI_SORT_ASCENDING, "AmbientIlluminance");
290
291     return (Status);
292 }
293
294
295 /******************************************************************************
296  *
297  * FUNCTION:    AcpiNsRepair_FDE
298  *
299  * PARAMETERS:  Info                - Method execution information block
300  *              ReturnObjectPtr     - Pointer to the object returned from the
301  *                                    evaluation of a method or object
302  *
303  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
304  *
305  * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return
306  *              value is a Buffer of 5 DWORDs. This function repairs a common
307  *              problem where the return value is a Buffer of BYTEs, not
308  *              DWORDs.
309  *
310  *****************************************************************************/
311
312 static ACPI_STATUS
313 AcpiNsRepair_FDE (
314     ACPI_EVALUATE_INFO      *Info,
315     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
316 {
317     ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
318     ACPI_OPERAND_OBJECT     *BufferObject;
319     UINT8                   *ByteBuffer;
320     UINT32                  *DwordBuffer;
321     UINT32                  i;
322
323
324     ACPI_FUNCTION_NAME (NsRepair_FDE);
325
326
327     switch (ReturnObject->Common.Type)
328     {
329     case ACPI_TYPE_BUFFER:
330
331         /* This is the expected type. Length should be (at least) 5 DWORDs */
332
333         if (ReturnObject->Buffer.Length >= ACPI_FDE_DWORD_BUFFER_SIZE)
334         {
335             return (AE_OK);
336         }
337
338         /* We can only repair if we have exactly 5 BYTEs */
339
340         if (ReturnObject->Buffer.Length != ACPI_FDE_BYTE_BUFFER_SIZE)
341         {
342             ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
343                 "Incorrect return buffer length %u, expected %u",
344                 ReturnObject->Buffer.Length, ACPI_FDE_DWORD_BUFFER_SIZE));
345
346             return (AE_AML_OPERAND_TYPE);
347         }
348
349         /* Create the new (larger) buffer object */
350
351         BufferObject = AcpiUtCreateBufferObject (ACPI_FDE_DWORD_BUFFER_SIZE);
352         if (!BufferObject)
353         {
354             return (AE_NO_MEMORY);
355         }
356
357         /* Expand each byte to a DWORD */
358
359         ByteBuffer = ReturnObject->Buffer.Pointer;
360         DwordBuffer = ACPI_CAST_PTR (UINT32, BufferObject->Buffer.Pointer);
361
362         for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++)
363         {
364             *DwordBuffer = (UINT32) *ByteBuffer;
365             DwordBuffer++;
366             ByteBuffer++;
367         }
368
369         ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
370             "%s Expanded Byte Buffer to expected DWord Buffer\n",
371             Info->FullPathname));
372         break;
373
374     default:
375
376         return (AE_AML_OPERAND_TYPE);
377     }
378
379     /* Delete the original return object, return the new buffer object */
380
381     AcpiUtRemoveReference (ReturnObject);
382     *ReturnObjectPtr = BufferObject;
383
384     Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
385     return (AE_OK);
386 }
387
388
389 /******************************************************************************
390  *
391  * FUNCTION:    AcpiNsRepair_CID
392  *
393  * PARAMETERS:  Info                - Method execution information block
394  *              ReturnObjectPtr     - Pointer to the object returned from the
395  *                                    evaluation of a method or object
396  *
397  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
398  *
399  * DESCRIPTION: Repair for the _CID object. If a string, ensure that all
400  *              letters are uppercase and that there is no leading asterisk.
401  *              If a Package, ensure same for all string elements.
402  *
403  *****************************************************************************/
404
405 static ACPI_STATUS
406 AcpiNsRepair_CID (
407     ACPI_EVALUATE_INFO      *Info,
408     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
409 {
410     ACPI_STATUS             Status;
411     ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
412     ACPI_OPERAND_OBJECT     **ElementPtr;
413     ACPI_OPERAND_OBJECT     *OriginalElement;
414     UINT16                  OriginalRefCount;
415     UINT32                  i;
416
417
418     /* Check for _CID as a simple string */
419
420     if (ReturnObject->Common.Type == ACPI_TYPE_STRING)
421     {
422         Status = AcpiNsRepair_HID (Info, ReturnObjectPtr);
423         return (Status);
424     }
425
426     /* Exit if not a Package */
427
428     if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE)
429     {
430         return (AE_OK);
431     }
432
433     /* Examine each element of the _CID package */
434
435     ElementPtr = ReturnObject->Package.Elements;
436     for (i = 0; i < ReturnObject->Package.Count; i++)
437     {
438         OriginalElement = *ElementPtr;
439         OriginalRefCount = OriginalElement->Common.ReferenceCount;
440
441         Status = AcpiNsRepair_HID (Info, ElementPtr);
442         if (ACPI_FAILURE (Status))
443         {
444             return (Status);
445         }
446
447         /* Take care with reference counts */
448
449         if (OriginalElement != *ElementPtr)
450         {
451             /* Element was replaced */
452
453             (*ElementPtr)->Common.ReferenceCount =
454                 OriginalRefCount;
455
456             AcpiUtRemoveReference (OriginalElement);
457         }
458
459         ElementPtr++;
460     }
461
462     return (AE_OK);
463 }
464
465
466 /******************************************************************************
467  *
468  * FUNCTION:    AcpiNsRepair_CST
469  *
470  * PARAMETERS:  Info                - Method execution information block
471  *              ReturnObjectPtr     - Pointer to the object returned from the
472  *                                    evaluation of a method or object
473  *
474  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
475  *
476  * DESCRIPTION: Repair for the _CST object:
477  *              1. Sort the list ascending by C state type
478  *              2. Ensure type cannot be zero
479  *              3. A subpackage count of zero means _CST is meaningless
480  *              4. Count must match the number of C state subpackages
481  *
482  *****************************************************************************/
483
484 static ACPI_STATUS
485 AcpiNsRepair_CST (
486     ACPI_EVALUATE_INFO      *Info,
487     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
488 {
489     ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
490     ACPI_OPERAND_OBJECT     **OuterElements;
491     UINT32                  OuterElementCount;
492     ACPI_OPERAND_OBJECT     *ObjDesc;
493     ACPI_STATUS             Status;
494     BOOLEAN                 Removing;
495     UINT32                  i;
496
497
498     ACPI_FUNCTION_NAME (NsRepair_CST);
499
500
501     /*
502      * Check if the C-state type values are proportional.
503      */
504     OuterElementCount = ReturnObject->Package.Count - 1;
505     i = 0;
506     while (i < OuterElementCount)
507     {
508         OuterElements = &ReturnObject->Package.Elements[i + 1];
509         Removing = FALSE;
510
511         if ((*OuterElements)->Package.Count == 0)
512         {
513             ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
514                 "SubPackage[%u] - removing entry due to zero count", i));
515             Removing = TRUE;
516             goto RemoveElement;
517         }
518
519         ObjDesc = (*OuterElements)->Package.Elements[1]; /* Index1 = Type */
520         if ((UINT32) ObjDesc->Integer.Value == 0)
521         {
522             ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
523                 "SubPackage[%u] - removing entry due to invalid Type(0)", i));
524             Removing = TRUE;
525         }
526
527 RemoveElement:
528         if (Removing)
529         {
530             AcpiNsRemoveElement (ReturnObject, i + 1);
531             OuterElementCount--;
532         }
533         else
534         {
535             i++;
536         }
537     }
538
539     /* Update top-level package count, Type "Integer" checked elsewhere */
540
541     ObjDesc = ReturnObject->Package.Elements[0];
542     ObjDesc->Integer.Value = OuterElementCount;
543
544     /*
545      * Entries (subpackages) in the _CST Package must be sorted by the
546      * C-state type, in ascending order.
547      */
548     Status = AcpiNsCheckSortedList (Info, ReturnObject, 1, 4, 1,
549                 ACPI_SORT_ASCENDING, "C-State Type");
550     if (ACPI_FAILURE (Status))
551     {
552         return (Status);
553     }
554
555     return (AE_OK);
556 }
557
558
559 /******************************************************************************
560  *
561  * FUNCTION:    AcpiNsRepair_HID
562  *
563  * PARAMETERS:  Info                - Method execution information block
564  *              ReturnObjectPtr     - Pointer to the object returned from the
565  *                                    evaluation of a method or object
566  *
567  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
568  *
569  * DESCRIPTION: Repair for the _HID object. If a string, ensure that all
570  *              letters are uppercase and that there is no leading asterisk.
571  *
572  *****************************************************************************/
573
574 static ACPI_STATUS
575 AcpiNsRepair_HID (
576     ACPI_EVALUATE_INFO      *Info,
577     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
578 {
579     ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
580     ACPI_OPERAND_OBJECT     *NewString;
581     char                    *Source;
582     char                    *Dest;
583
584
585     ACPI_FUNCTION_NAME (NsRepair_HID);
586
587
588     /* We only care about string _HID objects (not integers) */
589
590     if (ReturnObject->Common.Type != ACPI_TYPE_STRING)
591     {
592         return (AE_OK);
593     }
594
595     if (ReturnObject->String.Length == 0)
596     {
597         ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
598             "Invalid zero-length _HID or _CID string"));
599
600         /* Return AE_OK anyway, let driver handle it */
601
602         Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
603         return (AE_OK);
604     }
605
606     /* It is simplest to always create a new string object */
607
608     NewString = AcpiUtCreateStringObject (ReturnObject->String.Length);
609     if (!NewString)
610     {
611         return (AE_NO_MEMORY);
612     }
613
614     /*
615      * Remove a leading asterisk if present. For some unknown reason, there
616      * are many machines in the field that contains IDs like this.
617      *
618      * Examples: "*PNP0C03", "*ACPI0003"
619      */
620     Source = ReturnObject->String.Pointer;
621     if (*Source == '*')
622     {
623         Source++;
624         NewString->String.Length--;
625
626         ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
627             "%s: Removed invalid leading asterisk\n", Info->FullPathname));
628     }
629
630     /*
631      * Copy and uppercase the string. From the ACPI 5.0 specification:
632      *
633      * A valid PNP ID must be of the form "AAA####" where A is an uppercase
634      * letter and # is a hex digit. A valid ACPI ID must be of the form
635      * "NNNN####" where N is an uppercase letter or decimal digit, and
636      * # is a hex digit.
637      */
638     for (Dest = NewString->String.Pointer; *Source; Dest++, Source++)
639     {
640         *Dest = (char) ACPI_TOUPPER (*Source);
641     }
642
643     AcpiUtRemoveReference (ReturnObject);
644     *ReturnObjectPtr = NewString;
645     return (AE_OK);
646 }
647
648
649 /******************************************************************************
650  *
651  * FUNCTION:    AcpiNsRepair_PRT
652  *
653  * PARAMETERS:  Info                - Method execution information block
654  *              ReturnObjectPtr     - Pointer to the object returned from the
655  *                                    evaluation of a method or object
656  *
657  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
658  *
659  * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed
660  *              SourceName and SourceIndex field, a common BIOS bug.
661  *
662  *****************************************************************************/
663
664 static ACPI_STATUS
665 AcpiNsRepair_PRT (
666     ACPI_EVALUATE_INFO      *Info,
667     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
668 {
669     ACPI_OPERAND_OBJECT     *PackageObject = *ReturnObjectPtr;
670     ACPI_OPERAND_OBJECT     **TopObjectList;
671     ACPI_OPERAND_OBJECT     **SubObjectList;
672     ACPI_OPERAND_OBJECT     *ObjDesc;
673     ACPI_OPERAND_OBJECT     *SubPackage;
674     UINT32                  ElementCount;
675     UINT32                  Index;
676
677
678     /* Each element in the _PRT package is a subpackage */
679
680     TopObjectList = PackageObject->Package.Elements;
681     ElementCount = PackageObject->Package.Count;
682
683     /* Examine each subpackage */
684
685     for (Index = 0; Index < ElementCount; Index++, TopObjectList++)
686     {
687         SubPackage = *TopObjectList;
688         SubObjectList = SubPackage->Package.Elements;
689
690         /* Check for minimum required element count */
691
692         if (SubPackage->Package.Count < 4)
693         {
694             continue;
695         }
696
697         /*
698          * If the BIOS has erroneously reversed the _PRT SourceName (index 2)
699          * and the SourceIndex (index 3), fix it. _PRT is important enough to
700          * workaround this BIOS error. This also provides compatibility with
701          * other ACPI implementations.
702          */
703         ObjDesc = SubObjectList[3];
704         if (!ObjDesc || (ObjDesc->Common.Type != ACPI_TYPE_INTEGER))
705         {
706             SubObjectList[3] = SubObjectList[2];
707             SubObjectList[2] = ObjDesc;
708             Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
709
710             ACPI_WARN_PREDEFINED ((AE_INFO,
711                 Info->FullPathname, Info->NodeFlags,
712                 "PRT[%X]: Fixed reversed SourceName and SourceIndex",
713                 Index));
714         }
715     }
716
717     return (AE_OK);
718 }
719
720
721 /******************************************************************************
722  *
723  * FUNCTION:    AcpiNsRepair_PSS
724  *
725  * PARAMETERS:  Info                - Method execution information block
726  *              ReturnObjectPtr     - Pointer to the object returned from the
727  *                                    evaluation of a method or object
728  *
729  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
730  *
731  * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list
732  *              by the CPU frequencies. Check that the power dissipation values
733  *              are all proportional to CPU frequency (i.e., sorting by
734  *              frequency should be the same as sorting by power.)
735  *
736  *****************************************************************************/
737
738 static ACPI_STATUS
739 AcpiNsRepair_PSS (
740     ACPI_EVALUATE_INFO      *Info,
741     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
742 {
743     ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
744     ACPI_OPERAND_OBJECT     **OuterElements;
745     UINT32                  OuterElementCount;
746     ACPI_OPERAND_OBJECT     **Elements;
747     ACPI_OPERAND_OBJECT     *ObjDesc;
748     UINT32                  PreviousValue;
749     ACPI_STATUS             Status;
750     UINT32                  i;
751
752
753     /*
754      * Entries (subpackages) in the _PSS Package must be sorted by power
755      * dissipation, in descending order. If it appears that the list is
756      * incorrectly sorted, sort it. We sort by CpuFrequency, since this
757      * should be proportional to the power.
758      */
759     Status =AcpiNsCheckSortedList (Info, ReturnObject, 0, 6, 0,
760                 ACPI_SORT_DESCENDING, "CpuFrequency");
761     if (ACPI_FAILURE (Status))
762     {
763         return (Status);
764     }
765
766     /*
767      * We now know the list is correctly sorted by CPU frequency. Check if
768      * the power dissipation values are proportional.
769      */
770     PreviousValue = ACPI_UINT32_MAX;
771     OuterElements = ReturnObject->Package.Elements;
772     OuterElementCount = ReturnObject->Package.Count;
773
774     for (i = 0; i < OuterElementCount; i++)
775     {
776         Elements = (*OuterElements)->Package.Elements;
777         ObjDesc = Elements[1]; /* Index1 = PowerDissipation */
778
779         if ((UINT32) ObjDesc->Integer.Value > PreviousValue)
780         {
781             ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags,
782                 "SubPackage[%u,%u] - suspicious power dissipation values",
783                 i-1, i));
784         }
785
786         PreviousValue = (UINT32) ObjDesc->Integer.Value;
787         OuterElements++;
788     }
789
790     return (AE_OK);
791 }
792
793
794 /******************************************************************************
795  *
796  * FUNCTION:    AcpiNsRepair_TSS
797  *
798  * PARAMETERS:  Info                - Method execution information block
799  *              ReturnObjectPtr     - Pointer to the object returned from the
800  *                                    evaluation of a method or object
801  *
802  * RETURN:      Status. AE_OK if object is OK or was repaired successfully
803  *
804  * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
805  *              descending by the power dissipation values.
806  *
807  *****************************************************************************/
808
809 static ACPI_STATUS
810 AcpiNsRepair_TSS (
811     ACPI_EVALUATE_INFO      *Info,
812     ACPI_OPERAND_OBJECT     **ReturnObjectPtr)
813 {
814     ACPI_OPERAND_OBJECT     *ReturnObject = *ReturnObjectPtr;
815     ACPI_STATUS             Status;
816     ACPI_NAMESPACE_NODE     *Node;
817
818
819     /*
820      * We can only sort the _TSS return package if there is no _PSS in the
821      * same scope. This is because if _PSS is present, the ACPI specification
822      * dictates that the _TSS Power Dissipation field is to be ignored, and
823      * therefore some BIOSs leave garbage values in the _TSS Power field(s).
824      * In this case, it is best to just return the _TSS package as-is.
825      * (May, 2011)
826      */
827     Status = AcpiNsGetNode (Info->Node, "^_PSS",
828         ACPI_NS_NO_UPSEARCH, &Node);
829     if (ACPI_SUCCESS (Status))
830     {
831         return (AE_OK);
832     }
833
834     Status = AcpiNsCheckSortedList (Info, ReturnObject, 0, 5, 1,
835                 ACPI_SORT_DESCENDING, "PowerDissipation");
836
837     return (Status);
838 }
839
840
841 /******************************************************************************
842  *
843  * FUNCTION:    AcpiNsCheckSortedList
844  *
845  * PARAMETERS:  Info                - Method execution information block
846  *              ReturnObject        - Pointer to the top-level returned object
847  *              StartIndex          - Index of the first subpackage
848  *              ExpectedCount       - Minimum length of each subpackage
849  *              SortIndex           - Subpackage entry to sort on
850  *              SortDirection       - Ascending or descending
851  *              SortKeyName         - Name of the SortIndex field
852  *
853  * RETURN:      Status. AE_OK if the list is valid and is sorted correctly or
854  *              has been repaired by sorting the list.
855  *
856  * DESCRIPTION: Check if the package list is valid and sorted correctly by the
857  *              SortIndex. If not, then sort the list.
858  *
859  *****************************************************************************/
860
861 static ACPI_STATUS
862 AcpiNsCheckSortedList (
863     ACPI_EVALUATE_INFO      *Info,
864     ACPI_OPERAND_OBJECT     *ReturnObject,
865     UINT32                  StartIndex,
866     UINT32                  ExpectedCount,
867     UINT32                  SortIndex,
868     UINT8                   SortDirection,
869     char                    *SortKeyName)
870 {
871     UINT32                  OuterElementCount;
872     ACPI_OPERAND_OBJECT     **OuterElements;
873     ACPI_OPERAND_OBJECT     **Elements;
874     ACPI_OPERAND_OBJECT     *ObjDesc;
875     UINT32                  i;
876     UINT32                  PreviousValue;
877
878
879     ACPI_FUNCTION_NAME (NsCheckSortedList);
880
881
882     /* The top-level object must be a package */
883
884     if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE)
885     {
886         return (AE_AML_OPERAND_TYPE);
887     }
888
889     /*
890      * NOTE: assumes list of subpackages contains no NULL elements.
891      * Any NULL elements should have been removed by earlier call
892      * to AcpiNsRemoveNullElements.
893      */
894     OuterElementCount = ReturnObject->Package.Count;
895     if (!OuterElementCount || StartIndex >= OuterElementCount)
896     {
897         return (AE_AML_PACKAGE_LIMIT);
898     }
899
900     OuterElements = &ReturnObject->Package.Elements[StartIndex];
901     OuterElementCount -= StartIndex;
902
903     PreviousValue = 0;
904     if (SortDirection == ACPI_SORT_DESCENDING)
905     {
906         PreviousValue = ACPI_UINT32_MAX;
907     }
908
909     /* Examine each subpackage */
910
911     for (i = 0; i < OuterElementCount; i++)
912     {
913         /* Each element of the top-level package must also be a package */
914
915         if ((*OuterElements)->Common.Type != ACPI_TYPE_PACKAGE)
916         {
917             return (AE_AML_OPERAND_TYPE);
918         }
919
920         /* Each subpackage must have the minimum length */
921
922         if ((*OuterElements)->Package.Count < ExpectedCount)
923         {
924             return (AE_AML_PACKAGE_LIMIT);
925         }
926
927         Elements = (*OuterElements)->Package.Elements;
928         ObjDesc = Elements[SortIndex];
929
930         if (ObjDesc->Common.Type != ACPI_TYPE_INTEGER)
931         {
932             return (AE_AML_OPERAND_TYPE);
933         }
934
935         /*
936          * The list must be sorted in the specified order. If we detect a
937          * discrepancy, sort the entire list.
938          */
939         if (((SortDirection == ACPI_SORT_ASCENDING) &&
940                 (ObjDesc->Integer.Value < PreviousValue)) ||
941             ((SortDirection == ACPI_SORT_DESCENDING) &&
942                 (ObjDesc->Integer.Value > PreviousValue)))
943         {
944             AcpiNsSortList (&ReturnObject->Package.Elements[StartIndex],
945                 OuterElementCount, SortIndex, SortDirection);
946
947             Info->ReturnFlags |= ACPI_OBJECT_REPAIRED;
948
949             ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR,
950                 "%s: Repaired unsorted list - now sorted by %s\n",
951                 Info->FullPathname, SortKeyName));
952             return (AE_OK);
953         }
954
955         PreviousValue = (UINT32) ObjDesc->Integer.Value;
956         OuterElements++;
957     }
958
959     return (AE_OK);
960 }
961
962
963 /******************************************************************************
964  *
965  * FUNCTION:    AcpiNsSortList
966  *
967  * PARAMETERS:  Elements            - Package object element list
968  *              Count               - Element count for above
969  *              Index               - Sort by which package element
970  *              SortDirection       - Ascending or Descending sort
971  *
972  * RETURN:      None
973  *
974  * DESCRIPTION: Sort the objects that are in a package element list.
975  *
976  * NOTE: Assumes that all NULL elements have been removed from the package,
977  *       and that all elements have been verified to be of type Integer.
978  *
979  *****************************************************************************/
980
981 static void
982 AcpiNsSortList (
983     ACPI_OPERAND_OBJECT     **Elements,
984     UINT32                  Count,
985     UINT32                  Index,
986     UINT8                   SortDirection)
987 {
988     ACPI_OPERAND_OBJECT     *ObjDesc1;
989     ACPI_OPERAND_OBJECT     *ObjDesc2;
990     ACPI_OPERAND_OBJECT     *TempObj;
991     UINT32                  i;
992     UINT32                  j;
993
994
995     /* Simple bubble sort */
996
997     for (i = 1; i < Count; i++)
998     {
999         for (j = (Count - 1); j >= i; j--)
1000         {
1001             ObjDesc1 = Elements[j-1]->Package.Elements[Index];
1002             ObjDesc2 = Elements[j]->Package.Elements[Index];
1003
1004             if (((SortDirection == ACPI_SORT_ASCENDING) &&
1005                     (ObjDesc1->Integer.Value > ObjDesc2->Integer.Value)) ||
1006
1007                 ((SortDirection == ACPI_SORT_DESCENDING) &&
1008                     (ObjDesc1->Integer.Value < ObjDesc2->Integer.Value)))
1009             {
1010                 TempObj = Elements[j-1];
1011                 Elements[j-1] = Elements[j];
1012                 Elements[j] = TempObj;
1013             }
1014         }
1015     }
1016 }
1017
1018
1019 /******************************************************************************
1020  *
1021  * FUNCTION:    AcpiNsRemoveElement
1022  *
1023  * PARAMETERS:  ObjDesc             - Package object element list
1024  *              Index               - Index of element to remove
1025  *
1026  * RETURN:      None
1027  *
1028  * DESCRIPTION: Remove the requested element of a package and delete it.
1029  *
1030  *****************************************************************************/
1031
1032 static void
1033 AcpiNsRemoveElement (
1034     ACPI_OPERAND_OBJECT     *ObjDesc,
1035     UINT32                  Index)
1036 {
1037     ACPI_OPERAND_OBJECT     **Source;
1038     ACPI_OPERAND_OBJECT     **Dest;
1039     UINT32                  Count;
1040     UINT32                  NewCount;
1041     UINT32                  i;
1042
1043
1044     ACPI_FUNCTION_NAME (NsRemoveElement);
1045
1046
1047     Count = ObjDesc->Package.Count;
1048     NewCount = Count - 1;
1049
1050     Source = ObjDesc->Package.Elements;
1051     Dest = Source;
1052
1053     /* Examine all elements of the package object, remove matched index */
1054
1055     for (i = 0; i < Count; i++)
1056     {
1057         if (i == Index)
1058         {
1059             AcpiUtRemoveReference (*Source); /* Remove one ref for being in pkg */
1060             AcpiUtRemoveReference (*Source);
1061         }
1062         else
1063         {
1064             *Dest = *Source;
1065             Dest++;
1066         }
1067         Source++;
1068     }
1069
1070     /* NULL terminate list and update the package count */
1071
1072     *Dest = NULL;
1073     ObjDesc->Package.Count = NewCount;
1074 }