nsrepair2.c revision 249663
1/****************************************************************************** 2 * 3 * Module Name: nsrepair2 - Repair for objects returned by specific 4 * predefined methods 5 * 6 *****************************************************************************/ 7 8/* 9 * Copyright (C) 2000 - 2013, 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#define __NSREPAIR2_C__ 46 47#include <contrib/dev/acpica/include/acpi.h> 48#include <contrib/dev/acpica/include/accommon.h> 49#include <contrib/dev/acpica/include/acnamesp.h> 50 51#define _COMPONENT ACPI_NAMESPACE 52 ACPI_MODULE_NAME ("nsrepair2") 53 54 55/* 56 * Information structure and handler for ACPI predefined names that can 57 * be repaired on a per-name basis. 58 */ 59typedef 60ACPI_STATUS (*ACPI_REPAIR_FUNCTION) ( 61 ACPI_EVALUATE_INFO *Info, 62 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 63 64typedef struct acpi_repair_info 65{ 66 char Name[ACPI_NAME_SIZE]; 67 ACPI_REPAIR_FUNCTION RepairFunction; 68 69} ACPI_REPAIR_INFO; 70 71 72/* Local prototypes */ 73 74static const ACPI_REPAIR_INFO * 75AcpiNsMatchComplexRepair ( 76 ACPI_NAMESPACE_NODE *Node); 77 78static ACPI_STATUS 79AcpiNsRepair_ALR ( 80 ACPI_EVALUATE_INFO *Info, 81 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 82 83static ACPI_STATUS 84AcpiNsRepair_CID ( 85 ACPI_EVALUATE_INFO *Info, 86 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 87 88static ACPI_STATUS 89AcpiNsRepair_FDE ( 90 ACPI_EVALUATE_INFO *Info, 91 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 92 93static ACPI_STATUS 94AcpiNsRepair_HID ( 95 ACPI_EVALUATE_INFO *Info, 96 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 97 98static ACPI_STATUS 99AcpiNsRepair_PSS ( 100 ACPI_EVALUATE_INFO *Info, 101 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 102 103static ACPI_STATUS 104AcpiNsRepair_TSS ( 105 ACPI_EVALUATE_INFO *Info, 106 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 107 108static ACPI_STATUS 109AcpiNsCheckSortedList ( 110 ACPI_EVALUATE_INFO *Info, 111 ACPI_OPERAND_OBJECT *ReturnObject, 112 UINT32 ExpectedCount, 113 UINT32 SortIndex, 114 UINT8 SortDirection, 115 char *SortKeyName); 116 117static void 118AcpiNsSortList ( 119 ACPI_OPERAND_OBJECT **Elements, 120 UINT32 Count, 121 UINT32 Index, 122 UINT8 SortDirection); 123 124/* Values for SortDirection above */ 125 126#define ACPI_SORT_ASCENDING 0 127#define ACPI_SORT_DESCENDING 1 128 129 130/* 131 * This table contains the names of the predefined methods for which we can 132 * perform more complex repairs. 133 * 134 * As necessary: 135 * 136 * _ALR: Sort the list ascending by AmbientIlluminance 137 * _CID: Strings: uppercase all, remove any leading asterisk 138 * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs 139 * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs 140 * _HID: Strings: uppercase all, remove any leading asterisk 141 * _PSS: Sort the list descending by Power 142 * _TSS: Sort the list descending by Power 143 * 144 * Names that must be packages, but cannot be sorted: 145 * 146 * _BCL: Values are tied to the Package index where they appear, and cannot 147 * be moved or sorted. These index values are used for _BQC and _BCM. 148 * However, we can fix the case where a buffer is returned, by converting 149 * it to a Package of integers. 150 */ 151static const ACPI_REPAIR_INFO AcpiNsRepairableNames[] = 152{ 153 {"_ALR", AcpiNsRepair_ALR}, 154 {"_CID", AcpiNsRepair_CID}, 155 {"_FDE", AcpiNsRepair_FDE}, 156 {"_GTM", AcpiNsRepair_FDE}, /* _GTM has same repair as _FDE */ 157 {"_HID", AcpiNsRepair_HID}, 158 {"_PSS", AcpiNsRepair_PSS}, 159 {"_TSS", AcpiNsRepair_TSS}, 160 {{0,0,0,0}, NULL} /* Table terminator */ 161}; 162 163 164#define ACPI_FDE_FIELD_COUNT 5 165#define ACPI_FDE_BYTE_BUFFER_SIZE 5 166#define ACPI_FDE_DWORD_BUFFER_SIZE (ACPI_FDE_FIELD_COUNT * sizeof (UINT32)) 167 168 169/****************************************************************************** 170 * 171 * FUNCTION: AcpiNsComplexRepairs 172 * 173 * PARAMETERS: Info - Method execution information block 174 * Node - Namespace node for the method/object 175 * ValidateStatus - Original status of earlier validation 176 * ReturnObjectPtr - Pointer to the object returned from the 177 * evaluation of a method or object 178 * 179 * RETURN: Status. AE_OK if repair was successful. If name is not 180 * matched, ValidateStatus is returned. 181 * 182 * DESCRIPTION: Attempt to repair/convert a return object of a type that was 183 * not expected. 184 * 185 *****************************************************************************/ 186 187ACPI_STATUS 188AcpiNsComplexRepairs ( 189 ACPI_EVALUATE_INFO *Info, 190 ACPI_NAMESPACE_NODE *Node, 191 ACPI_STATUS ValidateStatus, 192 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 193{ 194 const ACPI_REPAIR_INFO *Predefined; 195 ACPI_STATUS Status; 196 197 198 /* Check if this name is in the list of repairable names */ 199 200 Predefined = AcpiNsMatchComplexRepair (Node); 201 if (!Predefined) 202 { 203 return (ValidateStatus); 204 } 205 206 Status = Predefined->RepairFunction (Info, ReturnObjectPtr); 207 return (Status); 208} 209 210 211/****************************************************************************** 212 * 213 * FUNCTION: AcpiNsMatchComplexRepair 214 * 215 * PARAMETERS: Node - Namespace node for the method/object 216 * 217 * RETURN: Pointer to entry in repair table. NULL indicates not found. 218 * 219 * DESCRIPTION: Check an object name against the repairable object list. 220 * 221 *****************************************************************************/ 222 223static const ACPI_REPAIR_INFO * 224AcpiNsMatchComplexRepair ( 225 ACPI_NAMESPACE_NODE *Node) 226{ 227 const ACPI_REPAIR_INFO *ThisName; 228 229 230 /* Search info table for a repairable predefined method/object name */ 231 232 ThisName = AcpiNsRepairableNames; 233 while (ThisName->RepairFunction) 234 { 235 if (ACPI_COMPARE_NAME (Node->Name.Ascii, ThisName->Name)) 236 { 237 return (ThisName); 238 } 239 ThisName++; 240 } 241 242 return (NULL); /* Not found */ 243} 244 245 246/****************************************************************************** 247 * 248 * FUNCTION: AcpiNsRepair_ALR 249 * 250 * PARAMETERS: Info - Method execution information block 251 * ReturnObjectPtr - Pointer to the object returned from the 252 * evaluation of a method or object 253 * 254 * RETURN: Status. AE_OK if object is OK or was repaired successfully 255 * 256 * DESCRIPTION: Repair for the _ALR object. If necessary, sort the object list 257 * ascending by the ambient illuminance values. 258 * 259 *****************************************************************************/ 260 261static ACPI_STATUS 262AcpiNsRepair_ALR ( 263 ACPI_EVALUATE_INFO *Info, 264 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 265{ 266 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 267 ACPI_STATUS Status; 268 269 270 Status = AcpiNsCheckSortedList (Info, ReturnObject, 2, 1, 271 ACPI_SORT_ASCENDING, "AmbientIlluminance"); 272 273 return (Status); 274} 275 276 277/****************************************************************************** 278 * 279 * FUNCTION: AcpiNsRepair_FDE 280 * 281 * PARAMETERS: Info - Method execution information block 282 * ReturnObjectPtr - Pointer to the object returned from the 283 * evaluation of a method or object 284 * 285 * RETURN: Status. AE_OK if object is OK or was repaired successfully 286 * 287 * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return 288 * value is a Buffer of 5 DWORDs. This function repairs a common 289 * problem where the return value is a Buffer of BYTEs, not 290 * DWORDs. 291 * 292 *****************************************************************************/ 293 294static ACPI_STATUS 295AcpiNsRepair_FDE ( 296 ACPI_EVALUATE_INFO *Info, 297 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 298{ 299 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 300 ACPI_OPERAND_OBJECT *BufferObject; 301 UINT8 *ByteBuffer; 302 UINT32 *DwordBuffer; 303 UINT32 i; 304 305 306 ACPI_FUNCTION_NAME (NsRepair_FDE); 307 308 309 switch (ReturnObject->Common.Type) 310 { 311 case ACPI_TYPE_BUFFER: 312 313 /* This is the expected type. Length should be (at least) 5 DWORDs */ 314 315 if (ReturnObject->Buffer.Length >= ACPI_FDE_DWORD_BUFFER_SIZE) 316 { 317 return (AE_OK); 318 } 319 320 /* We can only repair if we have exactly 5 BYTEs */ 321 322 if (ReturnObject->Buffer.Length != ACPI_FDE_BYTE_BUFFER_SIZE) 323 { 324 ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, 325 "Incorrect return buffer length %u, expected %u", 326 ReturnObject->Buffer.Length, ACPI_FDE_DWORD_BUFFER_SIZE)); 327 328 return (AE_AML_OPERAND_TYPE); 329 } 330 331 /* Create the new (larger) buffer object */ 332 333 BufferObject = AcpiUtCreateBufferObject (ACPI_FDE_DWORD_BUFFER_SIZE); 334 if (!BufferObject) 335 { 336 return (AE_NO_MEMORY); 337 } 338 339 /* Expand each byte to a DWORD */ 340 341 ByteBuffer = ReturnObject->Buffer.Pointer; 342 DwordBuffer = ACPI_CAST_PTR (UINT32, BufferObject->Buffer.Pointer); 343 344 for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) 345 { 346 *DwordBuffer = (UINT32) *ByteBuffer; 347 DwordBuffer++; 348 ByteBuffer++; 349 } 350 351 ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, 352 "%s Expanded Byte Buffer to expected DWord Buffer\n", 353 Info->FullPathname)); 354 break; 355 356 default: 357 return (AE_AML_OPERAND_TYPE); 358 } 359 360 /* Delete the original return object, return the new buffer object */ 361 362 AcpiUtRemoveReference (ReturnObject); 363 *ReturnObjectPtr = BufferObject; 364 365 Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; 366 return (AE_OK); 367} 368 369 370/****************************************************************************** 371 * 372 * FUNCTION: AcpiNsRepair_CID 373 * 374 * PARAMETERS: Info - Method execution information block 375 * ReturnObjectPtr - Pointer to the object returned from the 376 * evaluation of a method or object 377 * 378 * RETURN: Status. AE_OK if object is OK or was repaired successfully 379 * 380 * DESCRIPTION: Repair for the _CID object. If a string, ensure that all 381 * letters are uppercase and that there is no leading asterisk. 382 * If a Package, ensure same for all string elements. 383 * 384 *****************************************************************************/ 385 386static ACPI_STATUS 387AcpiNsRepair_CID ( 388 ACPI_EVALUATE_INFO *Info, 389 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 390{ 391 ACPI_STATUS Status; 392 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 393 ACPI_OPERAND_OBJECT **ElementPtr; 394 ACPI_OPERAND_OBJECT *OriginalElement; 395 UINT16 OriginalRefCount; 396 UINT32 i; 397 398 399 /* Check for _CID as a simple string */ 400 401 if (ReturnObject->Common.Type == ACPI_TYPE_STRING) 402 { 403 Status = AcpiNsRepair_HID (Info, ReturnObjectPtr); 404 return (Status); 405 } 406 407 /* Exit if not a Package */ 408 409 if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE) 410 { 411 return (AE_OK); 412 } 413 414 /* Examine each element of the _CID package */ 415 416 ElementPtr = ReturnObject->Package.Elements; 417 for (i = 0; i < ReturnObject->Package.Count; i++) 418 { 419 OriginalElement = *ElementPtr; 420 OriginalRefCount = OriginalElement->Common.ReferenceCount; 421 422 Status = AcpiNsRepair_HID (Info, ElementPtr); 423 if (ACPI_FAILURE (Status)) 424 { 425 return (Status); 426 } 427 428 /* Take care with reference counts */ 429 430 if (OriginalElement != *ElementPtr) 431 { 432 /* Element was replaced */ 433 434 (*ElementPtr)->Common.ReferenceCount = 435 OriginalRefCount; 436 437 AcpiUtRemoveReference (OriginalElement); 438 } 439 440 ElementPtr++; 441 } 442 443 return (AE_OK); 444} 445 446 447/****************************************************************************** 448 * 449 * FUNCTION: AcpiNsRepair_HID 450 * 451 * PARAMETERS: Info - Method execution information block 452 * ReturnObjectPtr - Pointer to the object returned from the 453 * evaluation of a method or object 454 * 455 * RETURN: Status. AE_OK if object is OK or was repaired successfully 456 * 457 * DESCRIPTION: Repair for the _HID object. If a string, ensure that all 458 * letters are uppercase and that there is no leading asterisk. 459 * 460 *****************************************************************************/ 461 462static ACPI_STATUS 463AcpiNsRepair_HID ( 464 ACPI_EVALUATE_INFO *Info, 465 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 466{ 467 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 468 ACPI_OPERAND_OBJECT *NewString; 469 char *Source; 470 char *Dest; 471 472 473 ACPI_FUNCTION_NAME (NsRepair_HID); 474 475 476 /* We only care about string _HID objects (not integers) */ 477 478 if (ReturnObject->Common.Type != ACPI_TYPE_STRING) 479 { 480 return (AE_OK); 481 } 482 483 if (ReturnObject->String.Length == 0) 484 { 485 ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, 486 "Invalid zero-length _HID or _CID string")); 487 488 /* Return AE_OK anyway, let driver handle it */ 489 490 Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; 491 return (AE_OK); 492 } 493 494 /* It is simplest to always create a new string object */ 495 496 NewString = AcpiUtCreateStringObject (ReturnObject->String.Length); 497 if (!NewString) 498 { 499 return (AE_NO_MEMORY); 500 } 501 502 /* 503 * Remove a leading asterisk if present. For some unknown reason, there 504 * are many machines in the field that contains IDs like this. 505 * 506 * Examples: "*PNP0C03", "*ACPI0003" 507 */ 508 Source = ReturnObject->String.Pointer; 509 if (*Source == '*') 510 { 511 Source++; 512 NewString->String.Length--; 513 514 ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, 515 "%s: Removed invalid leading asterisk\n", Info->FullPathname)); 516 } 517 518 /* 519 * Copy and uppercase the string. From the ACPI 5.0 specification: 520 * 521 * A valid PNP ID must be of the form "AAA####" where A is an uppercase 522 * letter and # is a hex digit. A valid ACPI ID must be of the form 523 * "NNNN####" where N is an uppercase letter or decimal digit, and 524 * # is a hex digit. 525 */ 526 for (Dest = NewString->String.Pointer; *Source; Dest++, Source++) 527 { 528 *Dest = (char) ACPI_TOUPPER (*Source); 529 } 530 531 AcpiUtRemoveReference (ReturnObject); 532 *ReturnObjectPtr = NewString; 533 return (AE_OK); 534} 535 536 537/****************************************************************************** 538 * 539 * FUNCTION: AcpiNsRepair_TSS 540 * 541 * PARAMETERS: Info - Method execution information block 542 * ReturnObjectPtr - Pointer to the object returned from the 543 * evaluation of a method or object 544 * 545 * RETURN: Status. AE_OK if object is OK or was repaired successfully 546 * 547 * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list 548 * descending by the power dissipation values. 549 * 550 *****************************************************************************/ 551 552static ACPI_STATUS 553AcpiNsRepair_TSS ( 554 ACPI_EVALUATE_INFO *Info, 555 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 556{ 557 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 558 ACPI_STATUS Status; 559 ACPI_NAMESPACE_NODE *Node; 560 561 562 /* 563 * We can only sort the _TSS return package if there is no _PSS in the 564 * same scope. This is because if _PSS is present, the ACPI specification 565 * dictates that the _TSS Power Dissipation field is to be ignored, and 566 * therefore some BIOSs leave garbage values in the _TSS Power field(s). 567 * In this case, it is best to just return the _TSS package as-is. 568 * (May, 2011) 569 */ 570 Status = AcpiNsGetNode (Info->Node, "^_PSS", 571 ACPI_NS_NO_UPSEARCH, &Node); 572 if (ACPI_SUCCESS (Status)) 573 { 574 return (AE_OK); 575 } 576 577 Status = AcpiNsCheckSortedList (Info, ReturnObject, 5, 1, 578 ACPI_SORT_DESCENDING, "PowerDissipation"); 579 580 return (Status); 581} 582 583 584/****************************************************************************** 585 * 586 * FUNCTION: AcpiNsRepair_PSS 587 * 588 * PARAMETERS: Info - Method execution information block 589 * ReturnObjectPtr - Pointer to the object returned from the 590 * evaluation of a method or object 591 * 592 * RETURN: Status. AE_OK if object is OK or was repaired successfully 593 * 594 * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list 595 * by the CPU frequencies. Check that the power dissipation values 596 * are all proportional to CPU frequency (i.e., sorting by 597 * frequency should be the same as sorting by power.) 598 * 599 *****************************************************************************/ 600 601static ACPI_STATUS 602AcpiNsRepair_PSS ( 603 ACPI_EVALUATE_INFO *Info, 604 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 605{ 606 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 607 ACPI_OPERAND_OBJECT **OuterElements; 608 UINT32 OuterElementCount; 609 ACPI_OPERAND_OBJECT **Elements; 610 ACPI_OPERAND_OBJECT *ObjDesc; 611 UINT32 PreviousValue; 612 ACPI_STATUS Status; 613 UINT32 i; 614 615 616 /* 617 * Entries (sub-packages) in the _PSS Package must be sorted by power 618 * dissipation, in descending order. If it appears that the list is 619 * incorrectly sorted, sort it. We sort by CpuFrequency, since this 620 * should be proportional to the power. 621 */ 622 Status =AcpiNsCheckSortedList (Info, ReturnObject, 6, 0, 623 ACPI_SORT_DESCENDING, "CpuFrequency"); 624 if (ACPI_FAILURE (Status)) 625 { 626 return (Status); 627 } 628 629 /* 630 * We now know the list is correctly sorted by CPU frequency. Check if 631 * the power dissipation values are proportional. 632 */ 633 PreviousValue = ACPI_UINT32_MAX; 634 OuterElements = ReturnObject->Package.Elements; 635 OuterElementCount = ReturnObject->Package.Count; 636 637 for (i = 0; i < OuterElementCount; i++) 638 { 639 Elements = (*OuterElements)->Package.Elements; 640 ObjDesc = Elements[1]; /* Index1 = PowerDissipation */ 641 642 if ((UINT32) ObjDesc->Integer.Value > PreviousValue) 643 { 644 ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, Info->NodeFlags, 645 "SubPackage[%u,%u] - suspicious power dissipation values", 646 i-1, i)); 647 } 648 649 PreviousValue = (UINT32) ObjDesc->Integer.Value; 650 OuterElements++; 651 } 652 653 return (AE_OK); 654} 655 656 657/****************************************************************************** 658 * 659 * FUNCTION: AcpiNsCheckSortedList 660 * 661 * PARAMETERS: Info - Method execution information block 662 * ReturnObject - Pointer to the top-level returned object 663 * ExpectedCount - Minimum length of each sub-package 664 * SortIndex - Sub-package entry to sort on 665 * SortDirection - Ascending or descending 666 * SortKeyName - Name of the SortIndex field 667 * 668 * RETURN: Status. AE_OK if the list is valid and is sorted correctly or 669 * has been repaired by sorting the list. 670 * 671 * DESCRIPTION: Check if the package list is valid and sorted correctly by the 672 * SortIndex. If not, then sort the list. 673 * 674 *****************************************************************************/ 675 676static ACPI_STATUS 677AcpiNsCheckSortedList ( 678 ACPI_EVALUATE_INFO *Info, 679 ACPI_OPERAND_OBJECT *ReturnObject, 680 UINT32 ExpectedCount, 681 UINT32 SortIndex, 682 UINT8 SortDirection, 683 char *SortKeyName) 684{ 685 UINT32 OuterElementCount; 686 ACPI_OPERAND_OBJECT **OuterElements; 687 ACPI_OPERAND_OBJECT **Elements; 688 ACPI_OPERAND_OBJECT *ObjDesc; 689 UINT32 i; 690 UINT32 PreviousValue; 691 692 693 ACPI_FUNCTION_NAME (NsCheckSortedList); 694 695 696 /* The top-level object must be a package */ 697 698 if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE) 699 { 700 return (AE_AML_OPERAND_TYPE); 701 } 702 703 /* 704 * NOTE: assumes list of sub-packages contains no NULL elements. 705 * Any NULL elements should have been removed by earlier call 706 * to AcpiNsRemoveNullElements. 707 */ 708 OuterElements = ReturnObject->Package.Elements; 709 OuterElementCount = ReturnObject->Package.Count; 710 if (!OuterElementCount) 711 { 712 return (AE_AML_PACKAGE_LIMIT); 713 } 714 715 PreviousValue = 0; 716 if (SortDirection == ACPI_SORT_DESCENDING) 717 { 718 PreviousValue = ACPI_UINT32_MAX; 719 } 720 721 /* Examine each subpackage */ 722 723 for (i = 0; i < OuterElementCount; i++) 724 { 725 /* Each element of the top-level package must also be a package */ 726 727 if ((*OuterElements)->Common.Type != ACPI_TYPE_PACKAGE) 728 { 729 return (AE_AML_OPERAND_TYPE); 730 } 731 732 /* Each sub-package must have the minimum length */ 733 734 if ((*OuterElements)->Package.Count < ExpectedCount) 735 { 736 return (AE_AML_PACKAGE_LIMIT); 737 } 738 739 Elements = (*OuterElements)->Package.Elements; 740 ObjDesc = Elements[SortIndex]; 741 742 if (ObjDesc->Common.Type != ACPI_TYPE_INTEGER) 743 { 744 return (AE_AML_OPERAND_TYPE); 745 } 746 747 /* 748 * The list must be sorted in the specified order. If we detect a 749 * discrepancy, sort the entire list. 750 */ 751 if (((SortDirection == ACPI_SORT_ASCENDING) && 752 (ObjDesc->Integer.Value < PreviousValue)) || 753 ((SortDirection == ACPI_SORT_DESCENDING) && 754 (ObjDesc->Integer.Value > PreviousValue))) 755 { 756 AcpiNsSortList (ReturnObject->Package.Elements, 757 OuterElementCount, SortIndex, SortDirection); 758 759 Info->ReturnFlags |= ACPI_OBJECT_REPAIRED; 760 761 ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, 762 "%s: Repaired unsorted list - now sorted by %s\n", 763 Info->FullPathname, SortKeyName)); 764 return (AE_OK); 765 } 766 767 PreviousValue = (UINT32) ObjDesc->Integer.Value; 768 OuterElements++; 769 } 770 771 return (AE_OK); 772} 773 774 775/****************************************************************************** 776 * 777 * FUNCTION: AcpiNsSortList 778 * 779 * PARAMETERS: Elements - Package object element list 780 * Count - Element count for above 781 * Index - Sort by which package element 782 * SortDirection - Ascending or Descending sort 783 * 784 * RETURN: None 785 * 786 * DESCRIPTION: Sort the objects that are in a package element list. 787 * 788 * NOTE: Assumes that all NULL elements have been removed from the package, 789 * and that all elements have been verified to be of type Integer. 790 * 791 *****************************************************************************/ 792 793static void 794AcpiNsSortList ( 795 ACPI_OPERAND_OBJECT **Elements, 796 UINT32 Count, 797 UINT32 Index, 798 UINT8 SortDirection) 799{ 800 ACPI_OPERAND_OBJECT *ObjDesc1; 801 ACPI_OPERAND_OBJECT *ObjDesc2; 802 ACPI_OPERAND_OBJECT *TempObj; 803 UINT32 i; 804 UINT32 j; 805 806 807 /* Simple bubble sort */ 808 809 for (i = 1; i < Count; i++) 810 { 811 for (j = (Count - 1); j >= i; j--) 812 { 813 ObjDesc1 = Elements[j-1]->Package.Elements[Index]; 814 ObjDesc2 = Elements[j]->Package.Elements[Index]; 815 816 if (((SortDirection == ACPI_SORT_ASCENDING) && 817 (ObjDesc1->Integer.Value > ObjDesc2->Integer.Value)) || 818 819 ((SortDirection == ACPI_SORT_DESCENDING) && 820 (ObjDesc1->Integer.Value < ObjDesc2->Integer.Value))) 821 { 822 TempObj = Elements[j-1]; 823 Elements[j-1] = Elements[j]; 824 Elements[j] = TempObj; 825 } 826 } 827 } 828} 829