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 */ 59 typedef 60 ACPI_STATUS (*ACPI_REPAIR_FUNCTION) ( 61 ACPI_PREDEFINED_DATA *Data, 62 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 63 64 typedef 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 74 static const ACPI_REPAIR_INFO * 75 AcpiNsMatchRepairableName ( 76 ACPI_NAMESPACE_NODE *Node); 77 78 static ACPI_STATUS 79 AcpiNsRepair_ALR ( 80 ACPI_PREDEFINED_DATA *Data, 81 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 82 83 static ACPI_STATUS 84 AcpiNsRepair_CID ( 85 ACPI_PREDEFINED_DATA *Data, 86 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 87 88 static ACPI_STATUS 89 AcpiNsRepair_FDE ( 90 ACPI_PREDEFINED_DATA *Data, 91 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 92 93 static ACPI_STATUS 94 AcpiNsRepair_HID ( 95 ACPI_PREDEFINED_DATA *Data, 96 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 97 98 static ACPI_STATUS 99 AcpiNsRepair_PSS ( 100 ACPI_PREDEFINED_DATA *Data, 101 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 102 103 static ACPI_STATUS 104 AcpiNsRepair_TSS ( 105 ACPI_PREDEFINED_DATA *Data, 106 ACPI_OPERAND_OBJECT **ReturnObjectPtr); 107 108 static ACPI_STATUS 109 AcpiNsCheckSortedList ( 110 ACPI_PREDEFINED_DATA *Data, 111 ACPI_OPERAND_OBJECT *ReturnObject, 112 UINT32 ExpectedCount, 113 UINT32 SortIndex, 114 UINT8 SortDirection, 115 char *SortKeyName); 116 117 static void 118 AcpiNsSortList ( 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 */ 151 static 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: Data - Pointer to validation data structure 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 187 ACPI_STATUS 188 AcpiNsComplexRepairs ( 189 ACPI_PREDEFINED_DATA *Data, 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 = AcpiNsMatchRepairableName (Node); 201 if (!Predefined) 202 { 203 return (ValidateStatus); 204 } 205 206 Status = Predefined->RepairFunction (Data, ReturnObjectPtr); 207 return (Status); 208 } 209 210 211 /****************************************************************************** 212 * 213 * FUNCTION: AcpiNsMatchRepairableName 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 223 static const ACPI_REPAIR_INFO * 224 AcpiNsMatchRepairableName ( 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: Data - Pointer to validation data structure 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 261 static ACPI_STATUS 262 AcpiNsRepair_ALR ( 263 ACPI_PREDEFINED_DATA *Data, 264 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 265 { 266 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 267 ACPI_STATUS Status; 268 269 270 Status = AcpiNsCheckSortedList (Data, ReturnObject, 2, 1, 271 ACPI_SORT_ASCENDING, "AmbientIlluminance"); 272 273 return (Status); 274 } 275 276 277 /****************************************************************************** 278 * 279 * FUNCTION: AcpiNsRepair_FDE 280 * 281 * PARAMETERS: Data - Pointer to validation data structure 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 294 static ACPI_STATUS 295 AcpiNsRepair_FDE ( 296 ACPI_PREDEFINED_DATA *Data, 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, Data->Pathname, Data->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 Data->Pathname)); 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 Data->Flags |= ACPI_OBJECT_REPAIRED; 366 return (AE_OK); 367 } 368 369 370 /****************************************************************************** 371 * 372 * FUNCTION: AcpiNsRepair_CID 373 * 374 * PARAMETERS: Data - Pointer to validation data structure 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 386 static ACPI_STATUS 387 AcpiNsRepair_CID ( 388 ACPI_PREDEFINED_DATA *Data, 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 (Data, 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 (Data, 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: Data - Pointer to validation data structure 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 462 static ACPI_STATUS 463 AcpiNsRepair_HID ( 464 ACPI_PREDEFINED_DATA *Data, 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, Data->Pathname, Data->NodeFlags, 486 "Invalid zero-length _HID or _CID string")); 487 488 /* Return AE_OK anyway, let driver handle it */ 489 490 Data->Flags |= 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", Data->Pathname)); 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: Data - Pointer to validation data structure 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 552 static ACPI_STATUS 553 AcpiNsRepair_TSS ( 554 ACPI_PREDEFINED_DATA *Data, 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 (Data->Node, "^_PSS", ACPI_NS_NO_UPSEARCH, &Node); 571 if (ACPI_SUCCESS (Status)) 572 { 573 return (AE_OK); 574 } 575 576 Status = AcpiNsCheckSortedList (Data, ReturnObject, 5, 1, 577 ACPI_SORT_DESCENDING, "PowerDissipation"); 578 579 return (Status); 580 } 581 582 583 /****************************************************************************** 584 * 585 * FUNCTION: AcpiNsRepair_PSS 586 * 587 * PARAMETERS: Data - Pointer to validation data structure 588 * ReturnObjectPtr - Pointer to the object returned from the 589 * evaluation of a method or object 590 * 591 * RETURN: Status. AE_OK if object is OK or was repaired successfully 592 * 593 * DESCRIPTION: Repair for the _PSS object. If necessary, sort the object list 594 * by the CPU frequencies. Check that the power dissipation values 595 * are all proportional to CPU frequency (i.e., sorting by 596 * frequency should be the same as sorting by power.) 597 * 598 *****************************************************************************/ 599 600 static ACPI_STATUS 601 AcpiNsRepair_PSS ( 602 ACPI_PREDEFINED_DATA *Data, 603 ACPI_OPERAND_OBJECT **ReturnObjectPtr) 604 { 605 ACPI_OPERAND_OBJECT *ReturnObject = *ReturnObjectPtr; 606 ACPI_OPERAND_OBJECT **OuterElements; 607 UINT32 OuterElementCount; 608 ACPI_OPERAND_OBJECT **Elements; 609 ACPI_OPERAND_OBJECT *ObjDesc; 610 UINT32 PreviousValue; 611 ACPI_STATUS Status; 612 UINT32 i; 613 614 615 /* 616 * Entries (sub-packages) in the _PSS Package must be sorted by power 617 * dissipation, in descending order. If it appears that the list is 618 * incorrectly sorted, sort it. We sort by CpuFrequency, since this 619 * should be proportional to the power. 620 */ 621 Status =AcpiNsCheckSortedList (Data, ReturnObject, 6, 0, 622 ACPI_SORT_DESCENDING, "CpuFrequency"); 623 if (ACPI_FAILURE (Status)) 624 { 625 return (Status); 626 } 627 628 /* 629 * We now know the list is correctly sorted by CPU frequency. Check if 630 * the power dissipation values are proportional. 631 */ 632 PreviousValue = ACPI_UINT32_MAX; 633 OuterElements = ReturnObject->Package.Elements; 634 OuterElementCount = ReturnObject->Package.Count; 635 636 for (i = 0; i < OuterElementCount; i++) 637 { 638 Elements = (*OuterElements)->Package.Elements; 639 ObjDesc = Elements[1]; /* Index1 = PowerDissipation */ 640 641 if ((UINT32) ObjDesc->Integer.Value > PreviousValue) 642 { 643 ACPI_WARN_PREDEFINED ((AE_INFO, Data->Pathname, Data->NodeFlags, 644 "SubPackage[%u,%u] - suspicious power dissipation values", 645 i-1, i)); 646 } 647 648 PreviousValue = (UINT32) ObjDesc->Integer.Value; 649 OuterElements++; 650 } 651 652 return (AE_OK); 653 } 654 655 656 /****************************************************************************** 657 * 658 * FUNCTION: AcpiNsCheckSortedList 659 * 660 * PARAMETERS: Data - Pointer to validation data structure 661 * ReturnObject - Pointer to the top-level returned object 662 * ExpectedCount - Minimum length of each sub-package 663 * SortIndex - Sub-package entry to sort on 664 * SortDirection - Ascending or descending 665 * SortKeyName - Name of the SortIndex field 666 * 667 * RETURN: Status. AE_OK if the list is valid and is sorted correctly or 668 * has been repaired by sorting the list. 669 * 670 * DESCRIPTION: Check if the package list is valid and sorted correctly by the 671 * SortIndex. If not, then sort the list. 672 * 673 *****************************************************************************/ 674 675 static ACPI_STATUS 676 AcpiNsCheckSortedList ( 677 ACPI_PREDEFINED_DATA *Data, 678 ACPI_OPERAND_OBJECT *ReturnObject, 679 UINT32 ExpectedCount, 680 UINT32 SortIndex, 681 UINT8 SortDirection, 682 char *SortKeyName) 683 { 684 UINT32 OuterElementCount; 685 ACPI_OPERAND_OBJECT **OuterElements; 686 ACPI_OPERAND_OBJECT **Elements; 687 ACPI_OPERAND_OBJECT *ObjDesc; 688 UINT32 i; 689 UINT32 PreviousValue; 690 691 692 ACPI_FUNCTION_NAME (NsCheckSortedList); 693 694 695 /* The top-level object must be a package */ 696 697 if (ReturnObject->Common.Type != ACPI_TYPE_PACKAGE) 698 { 699 return (AE_AML_OPERAND_TYPE); 700 } 701 702 /* 703 * NOTE: assumes list of sub-packages contains no NULL elements. 704 * Any NULL elements should have been removed by earlier call 705 * to AcpiNsRemoveNullElements. 706 */ 707 OuterElements = ReturnObject->Package.Elements; 708 OuterElementCount = ReturnObject->Package.Count; 709 if (!OuterElementCount) 710 { 711 return (AE_AML_PACKAGE_LIMIT); 712 } 713 714 PreviousValue = 0; 715 if (SortDirection == ACPI_SORT_DESCENDING) 716 { 717 PreviousValue = ACPI_UINT32_MAX; 718 } 719 720 /* Examine each subpackage */ 721 722 for (i = 0; i < OuterElementCount; i++) 723 { 724 /* Each element of the top-level package must also be a package */ 725 726 if ((*OuterElements)->Common.Type != ACPI_TYPE_PACKAGE) 727 { 728 return (AE_AML_OPERAND_TYPE); 729 } 730 731 /* Each sub-package must have the minimum length */ 732 733 if ((*OuterElements)->Package.Count < ExpectedCount) 734 { 735 return (AE_AML_PACKAGE_LIMIT); 736 } 737 738 Elements = (*OuterElements)->Package.Elements; 739 ObjDesc = Elements[SortIndex]; 740 741 if (ObjDesc->Common.Type != ACPI_TYPE_INTEGER) 742 { 743 return (AE_AML_OPERAND_TYPE); 744 } 745 746 /* 747 * The list must be sorted in the specified order. If we detect a 748 * discrepancy, sort the entire list. 749 */ 750 if (((SortDirection == ACPI_SORT_ASCENDING) && 751 (ObjDesc->Integer.Value < PreviousValue)) || 752 ((SortDirection == ACPI_SORT_DESCENDING) && 753 (ObjDesc->Integer.Value > PreviousValue))) 754 { 755 AcpiNsSortList (ReturnObject->Package.Elements, 756 OuterElementCount, SortIndex, SortDirection); 757 758 Data->Flags |= ACPI_OBJECT_REPAIRED; 759 760 ACPI_DEBUG_PRINT ((ACPI_DB_REPAIR, 761 "%s: Repaired unsorted list - now sorted by %s\n", 762 Data->Pathname, SortKeyName)); 763 return (AE_OK); 764 } 765 766 PreviousValue = (UINT32) ObjDesc->Integer.Value; 767 OuterElements++; 768 } 769 770 return (AE_OK); 771 } 772 773 774 /****************************************************************************** 775 * 776 * FUNCTION: AcpiNsSortList 777 * 778 * PARAMETERS: Elements - Package object element list 779 * Count - Element count for above 780 * Index - Sort by which package element 781 * SortDirection - Ascending or Descending sort 782 * 783 * RETURN: None 784 * 785 * DESCRIPTION: Sort the objects that are in a package element list. 786 * 787 * NOTE: Assumes that all NULL elements have been removed from the package, 788 * and that all elements have been verified to be of type Integer. 789 * 790 *****************************************************************************/ 791 792 static void 793 AcpiNsSortList ( 794 ACPI_OPERAND_OBJECT **Elements, 795 UINT32 Count, 796 UINT32 Index, 797 UINT8 SortDirection) 798 { 799 ACPI_OPERAND_OBJECT *ObjDesc1; 800 ACPI_OPERAND_OBJECT *ObjDesc2; 801 ACPI_OPERAND_OBJECT *TempObj; 802 UINT32 i; 803 UINT32 j; 804 805 806 /* Simple bubble sort */ 807 808 for (i = 1; i < Count; i++) 809 { 810 for (j = (Count - 1); j >= i; j--) 811 { 812 ObjDesc1 = Elements[j-1]->Package.Elements[Index]; 813 ObjDesc2 = Elements[j]->Package.Elements[Index]; 814 815 if (((SortDirection == ACPI_SORT_ASCENDING) && 816 (ObjDesc1->Integer.Value > ObjDesc2->Integer.Value)) || 817 818 ((SortDirection == ACPI_SORT_DESCENDING) && 819 (ObjDesc1->Integer.Value < ObjDesc2->Integer.Value))) 820 { 821 TempObj = Elements[j-1]; 822 Elements[j-1] = Elements[j]; 823 Elements[j] = TempObj; 824 } 825 } 826 } 827 } 828