1/****************************************************************************** 2 * 3 * Module Name: evgpeblk - GPE block creation and initialization. 4 * 5 *****************************************************************************/ 6 7/****************************************************************************** 8 * 9 * 1. Copyright Notice 10 * 11 * Some or all of this work - Copyright (c) 1999 - 2009, Intel Corp. 12 * All rights reserved. 13 * 14 * 2. License 15 * 16 * 2.1. This is your license from Intel Corp. under its intellectual property 17 * rights. You may have additional license terms from the party that provided 18 * you this software, covering your right to use that party's intellectual 19 * property rights. 20 * 21 * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a 22 * copy of the source code appearing in this file ("Covered Code") an 23 * irrevocable, perpetual, worldwide license under Intel's copyrights in the 24 * base code distributed originally by Intel ("Original Intel Code") to copy, 25 * make derivatives, distribute, use and display any portion of the Covered 26 * Code in any form, with the right to sublicense such rights; and 27 * 28 * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent 29 * license (with the right to sublicense), under only those claims of Intel 30 * patents that are infringed by the Original Intel Code, to make, use, sell, 31 * offer to sell, and import the Covered Code and derivative works thereof 32 * solely to the minimum extent necessary to exercise the above copyright 33 * license, and in no event shall the patent license extend to any additions 34 * to or modifications of the Original Intel Code. No other license or right 35 * is granted directly or by implication, estoppel or otherwise; 36 * 37 * The above copyright and patent license is granted only if the following 38 * conditions are met: 39 * 40 * 3. Conditions 41 * 42 * 3.1. Redistribution of Source with Rights to Further Distribute Source. 43 * Redistribution of source code of any substantial portion of the Covered 44 * Code or modification with rights to further distribute source must include 45 * the above Copyright Notice, the above License, this list of Conditions, 46 * and the following Disclaimer and Export Compliance provision. In addition, 47 * Licensee must cause all Covered Code to which Licensee contributes to 48 * contain a file documenting the changes Licensee made to create that Covered 49 * Code and the date of any change. Licensee must include in that file the 50 * documentation of any changes made by any predecessor Licensee. Licensee 51 * must include a prominent statement that the modification is derived, 52 * directly or indirectly, from Original Intel Code. 53 * 54 * 3.2. Redistribution of Source with no Rights to Further Distribute Source. 55 * Redistribution of source code of any substantial portion of the Covered 56 * Code or modification without rights to further distribute source must 57 * include the following Disclaimer and Export Compliance provision in the 58 * documentation and/or other materials provided with distribution. In 59 * addition, Licensee may not authorize further sublicense of source of any 60 * portion of the Covered Code, and must include terms to the effect that the 61 * license from Licensee to its licensee is limited to the intellectual 62 * property embodied in the software Licensee provides to its licensee, and 63 * not to intellectual property embodied in modifications its licensee may 64 * make. 65 * 66 * 3.3. Redistribution of Executable. Redistribution in executable form of any 67 * substantial portion of the Covered Code or modification must reproduce the 68 * above Copyright Notice, and the following Disclaimer and Export Compliance 69 * provision in the documentation and/or other materials provided with the 70 * distribution. 71 * 72 * 3.4. Intel retains all right, title, and interest in and to the Original 73 * Intel Code. 74 * 75 * 3.5. Neither the name Intel nor any other trademark owned or controlled by 76 * Intel shall be used in advertising or otherwise to promote the sale, use or 77 * other dealings in products derived from or relating to the Covered Code 78 * without prior written authorization from Intel. 79 * 80 * 4. Disclaimer and Export Compliance 81 * 82 * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED 83 * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE 84 * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, 85 * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY 86 * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY 87 * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A 88 * PARTICULAR PURPOSE. 89 * 90 * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES 91 * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR 92 * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, 93 * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY 94 * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL 95 * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS 96 * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY 97 * LIMITED REMEDY. 98 * 99 * 4.3. Licensee shall not export, either directly or indirectly, any of this 100 * software or system incorporating such software without first obtaining any 101 * required license or other approval from the U. S. Department of Commerce or 102 * any other agency or department of the United States Government. In the 103 * event Licensee exports any such software from the United States or 104 * re-exports any such software from a foreign destination, Licensee shall 105 * ensure that the distribution and export/re-export of the software is in 106 * compliance with all laws, regulations, orders, or other restrictions of the 107 * U.S. Export Administration Regulations. Licensee agrees that neither it nor 108 * any of its subsidiaries will export/re-export any technical data, process, 109 * software, or service, directly or indirectly, to any country for which the 110 * United States government or any agency thereof requires an export license, 111 * other governmental approval, or letter of assurance, without first obtaining 112 * such license, approval or letter. 113 * 114 *****************************************************************************/ 115 116#include <contrib/dev/acpica/include/acpi.h> 117#include <contrib/dev/acpica/include/accommon.h> 118#include <contrib/dev/acpica/include/acevents.h> 119#include <contrib/dev/acpica/include/acnamesp.h> 120 121#define _COMPONENT ACPI_EVENTS 122 ACPI_MODULE_NAME ("evgpeblk") 123 124/* Local prototypes */ 125 126static ACPI_STATUS 127AcpiEvSaveMethodInfo ( 128 ACPI_HANDLE ObjHandle, 129 UINT32 Level, 130 void *ObjDesc, 131 void **ReturnValue); 132 133static ACPI_STATUS 134AcpiEvMatchPrwAndGpe ( 135 ACPI_HANDLE ObjHandle, 136 UINT32 Level, 137 void *Info, 138 void **ReturnValue); 139 140static ACPI_GPE_XRUPT_INFO * 141AcpiEvGetGpeXruptBlock ( 142 UINT32 InterruptNumber); 143 144static ACPI_STATUS 145AcpiEvDeleteGpeXrupt ( 146 ACPI_GPE_XRUPT_INFO *GpeXrupt); 147 148static ACPI_STATUS 149AcpiEvInstallGpeBlock ( 150 ACPI_GPE_BLOCK_INFO *GpeBlock, 151 UINT32 InterruptNumber); 152 153static ACPI_STATUS 154AcpiEvCreateGpeInfoBlocks ( 155 ACPI_GPE_BLOCK_INFO *GpeBlock); 156 157 158/******************************************************************************* 159 * 160 * FUNCTION: AcpiEvValidGpeEvent 161 * 162 * PARAMETERS: GpeEventInfo - Info for this GPE 163 * 164 * RETURN: TRUE if the GpeEvent is valid 165 * 166 * DESCRIPTION: Validate a GPE event. DO NOT CALL FROM INTERRUPT LEVEL. 167 * Should be called only when the GPE lists are semaphore locked 168 * and not subject to change. 169 * 170 ******************************************************************************/ 171 172BOOLEAN 173AcpiEvValidGpeEvent ( 174 ACPI_GPE_EVENT_INFO *GpeEventInfo) 175{ 176 ACPI_GPE_XRUPT_INFO *GpeXruptBlock; 177 ACPI_GPE_BLOCK_INFO *GpeBlock; 178 179 180 ACPI_FUNCTION_ENTRY (); 181 182 183 /* No need for spin lock since we are not changing any list elements */ 184 185 /* Walk the GPE interrupt levels */ 186 187 GpeXruptBlock = AcpiGbl_GpeXruptListHead; 188 while (GpeXruptBlock) 189 { 190 GpeBlock = GpeXruptBlock->GpeBlockListHead; 191 192 /* Walk the GPE blocks on this interrupt level */ 193 194 while (GpeBlock) 195 { 196 if ((&GpeBlock->EventInfo[0] <= GpeEventInfo) && 197 (&GpeBlock->EventInfo[((ACPI_SIZE) 198 GpeBlock->RegisterCount) * 8] > GpeEventInfo)) 199 { 200 return (TRUE); 201 } 202 203 GpeBlock = GpeBlock->Next; 204 } 205 206 GpeXruptBlock = GpeXruptBlock->Next; 207 } 208 209 return (FALSE); 210} 211 212 213/******************************************************************************* 214 * 215 * FUNCTION: AcpiEvWalkGpeList 216 * 217 * PARAMETERS: GpeWalkCallback - Routine called for each GPE block 218 * Context - Value passed to callback 219 * 220 * RETURN: Status 221 * 222 * DESCRIPTION: Walk the GPE lists. 223 * 224 ******************************************************************************/ 225 226ACPI_STATUS 227AcpiEvWalkGpeList ( 228 ACPI_GPE_CALLBACK GpeWalkCallback, 229 void *Context) 230{ 231 ACPI_GPE_BLOCK_INFO *GpeBlock; 232 ACPI_GPE_XRUPT_INFO *GpeXruptInfo; 233 ACPI_STATUS Status = AE_OK; 234 ACPI_CPU_FLAGS Flags; 235 236 237 ACPI_FUNCTION_TRACE (EvWalkGpeList); 238 239 240 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 241 242 /* Walk the interrupt level descriptor list */ 243 244 GpeXruptInfo = AcpiGbl_GpeXruptListHead; 245 while (GpeXruptInfo) 246 { 247 /* Walk all Gpe Blocks attached to this interrupt level */ 248 249 GpeBlock = GpeXruptInfo->GpeBlockListHead; 250 while (GpeBlock) 251 { 252 /* One callback per GPE block */ 253 254 Status = GpeWalkCallback (GpeXruptInfo, GpeBlock, Context); 255 if (ACPI_FAILURE (Status)) 256 { 257 if (Status == AE_CTRL_END) /* Callback abort */ 258 { 259 Status = AE_OK; 260 } 261 goto UnlockAndExit; 262 } 263 264 GpeBlock = GpeBlock->Next; 265 } 266 267 GpeXruptInfo = GpeXruptInfo->Next; 268 } 269 270UnlockAndExit: 271 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 272 return_ACPI_STATUS (Status); 273} 274 275 276/******************************************************************************* 277 * 278 * FUNCTION: AcpiEvDeleteGpeHandlers 279 * 280 * PARAMETERS: GpeXruptInfo - GPE Interrupt info 281 * GpeBlock - Gpe Block info 282 * 283 * RETURN: Status 284 * 285 * DESCRIPTION: Delete all Handler objects found in the GPE data structs. 286 * Used only prior to termination. 287 * 288 ******************************************************************************/ 289 290ACPI_STATUS 291AcpiEvDeleteGpeHandlers ( 292 ACPI_GPE_XRUPT_INFO *GpeXruptInfo, 293 ACPI_GPE_BLOCK_INFO *GpeBlock, 294 void *Context) 295{ 296 ACPI_GPE_EVENT_INFO *GpeEventInfo; 297 UINT32 i; 298 UINT32 j; 299 300 301 ACPI_FUNCTION_TRACE (EvDeleteGpeHandlers); 302 303 304 /* Examine each GPE Register within the block */ 305 306 for (i = 0; i < GpeBlock->RegisterCount; i++) 307 { 308 /* Now look at the individual GPEs in this byte register */ 309 310 for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) 311 { 312 GpeEventInfo = &GpeBlock->EventInfo[((ACPI_SIZE) i * 313 ACPI_GPE_REGISTER_WIDTH) + j]; 314 315 if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) == 316 ACPI_GPE_DISPATCH_HANDLER) 317 { 318 ACPI_FREE (GpeEventInfo->Dispatch.Handler); 319 GpeEventInfo->Dispatch.Handler = NULL; 320 GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK; 321 } 322 } 323 } 324 325 return_ACPI_STATUS (AE_OK); 326} 327 328 329/******************************************************************************* 330 * 331 * FUNCTION: AcpiEvSaveMethodInfo 332 * 333 * PARAMETERS: Callback from WalkNamespace 334 * 335 * RETURN: Status 336 * 337 * DESCRIPTION: Called from AcpiWalkNamespace. Expects each object to be a 338 * control method under the _GPE portion of the namespace. 339 * Extract the name and GPE type from the object, saving this 340 * information for quick lookup during GPE dispatch 341 * 342 * The name of each GPE control method is of the form: 343 * "_Lxx" or "_Exx" 344 * Where: 345 * L - means that the GPE is level triggered 346 * E - means that the GPE is edge triggered 347 * xx - is the GPE number [in HEX] 348 * 349 ******************************************************************************/ 350 351static ACPI_STATUS 352AcpiEvSaveMethodInfo ( 353 ACPI_HANDLE ObjHandle, 354 UINT32 Level, 355 void *ObjDesc, 356 void **ReturnValue) 357{ 358 ACPI_GPE_BLOCK_INFO *GpeBlock = (void *) ObjDesc; 359 ACPI_GPE_EVENT_INFO *GpeEventInfo; 360 UINT32 GpeNumber; 361 char Name[ACPI_NAME_SIZE + 1]; 362 UINT8 Type; 363 ACPI_STATUS Status; 364 365 366 ACPI_FUNCTION_TRACE (EvSaveMethodInfo); 367 368 369 /* 370 * _Lxx and _Exx GPE method support 371 * 372 * 1) Extract the name from the object and convert to a string 373 */ 374 ACPI_MOVE_32_TO_32 ( 375 Name, &((ACPI_NAMESPACE_NODE *) ObjHandle)->Name.Integer); 376 Name[ACPI_NAME_SIZE] = 0; 377 378 /* 379 * 2) Edge/Level determination is based on the 2nd character 380 * of the method name 381 * 382 * NOTE: Default GPE type is RUNTIME. May be changed later to WAKE 383 * if a _PRW object is found that points to this GPE. 384 */ 385 switch (Name[1]) 386 { 387 case 'L': 388 Type = ACPI_GPE_LEVEL_TRIGGERED; 389 break; 390 391 case 'E': 392 Type = ACPI_GPE_EDGE_TRIGGERED; 393 break; 394 395 default: 396 /* Unknown method type, just ignore it! */ 397 398 ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, 399 "Ignoring unknown GPE method type: %s " 400 "(name not of form _Lxx or _Exx)", 401 Name)); 402 return_ACPI_STATUS (AE_OK); 403 } 404 405 /* Convert the last two characters of the name to the GPE Number */ 406 407 GpeNumber = ACPI_STRTOUL (&Name[2], NULL, 16); 408 if (GpeNumber == ACPI_UINT32_MAX) 409 { 410 /* Conversion failed; invalid method, just ignore it */ 411 412 ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, 413 "Could not extract GPE number from name: %s " 414 "(name is not of form _Lxx or _Exx)", 415 Name)); 416 return_ACPI_STATUS (AE_OK); 417 } 418 419 /* Ensure that we have a valid GPE number for this GPE block */ 420 421 if ((GpeNumber < GpeBlock->BlockBaseNumber) || 422 (GpeNumber >= (GpeBlock->BlockBaseNumber + 423 (GpeBlock->RegisterCount * 8)))) 424 { 425 /* 426 * Not valid for this GPE block, just ignore it. However, it may be 427 * valid for a different GPE block, since GPE0 and GPE1 methods both 428 * appear under \_GPE. 429 */ 430 return_ACPI_STATUS (AE_OK); 431 } 432 433 /* 434 * Now we can add this information to the GpeEventInfo block for use 435 * during dispatch of this GPE. Default type is RUNTIME, although this may 436 * change when the _PRW methods are executed later. 437 */ 438 GpeEventInfo = &GpeBlock->EventInfo[GpeNumber - GpeBlock->BlockBaseNumber]; 439 440 GpeEventInfo->Flags = (UINT8) 441 (Type | ACPI_GPE_DISPATCH_METHOD | ACPI_GPE_TYPE_RUNTIME); 442 443 GpeEventInfo->Dispatch.MethodNode = (ACPI_NAMESPACE_NODE *) ObjHandle; 444 445 /* Update enable mask, but don't enable the HW GPE as of yet */ 446 447 Status = AcpiEvEnableGpe (GpeEventInfo, FALSE); 448 449 ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, 450 "Registered GPE method %s as GPE number 0x%.2X\n", 451 Name, GpeNumber)); 452 return_ACPI_STATUS (Status); 453} 454 455 456/******************************************************************************* 457 * 458 * FUNCTION: AcpiEvMatchPrwAndGpe 459 * 460 * PARAMETERS: Callback from WalkNamespace 461 * 462 * RETURN: Status. NOTE: We ignore errors so that the _PRW walk is 463 * not aborted on a single _PRW failure. 464 * 465 * DESCRIPTION: Called from AcpiWalkNamespace. Expects each object to be a 466 * Device. Run the _PRW method. If present, extract the GPE 467 * number and mark the GPE as a WAKE GPE. 468 * 469 ******************************************************************************/ 470 471static ACPI_STATUS 472AcpiEvMatchPrwAndGpe ( 473 ACPI_HANDLE ObjHandle, 474 UINT32 Level, 475 void *Info, 476 void **ReturnValue) 477{ 478 ACPI_GPE_WALK_INFO *GpeInfo = (void *) Info; 479 ACPI_NAMESPACE_NODE *GpeDevice; 480 ACPI_GPE_BLOCK_INFO *GpeBlock; 481 ACPI_NAMESPACE_NODE *TargetGpeDevice; 482 ACPI_GPE_EVENT_INFO *GpeEventInfo; 483 ACPI_OPERAND_OBJECT *PkgDesc; 484 ACPI_OPERAND_OBJECT *ObjDesc; 485 UINT32 GpeNumber; 486 ACPI_STATUS Status; 487 488 489 ACPI_FUNCTION_TRACE (EvMatchPrwAndGpe); 490 491 492 /* Check for a _PRW method under this device */ 493 494 Status = AcpiUtEvaluateObject (ObjHandle, METHOD_NAME__PRW, 495 ACPI_BTYPE_PACKAGE, &PkgDesc); 496 if (ACPI_FAILURE (Status)) 497 { 498 /* Ignore all errors from _PRW, we don't want to abort the subsystem */ 499 500 return_ACPI_STATUS (AE_OK); 501 } 502 503 /* The returned _PRW package must have at least two elements */ 504 505 if (PkgDesc->Package.Count < 2) 506 { 507 goto Cleanup; 508 } 509 510 /* Extract pointers from the input context */ 511 512 GpeDevice = GpeInfo->GpeDevice; 513 GpeBlock = GpeInfo->GpeBlock; 514 515 /* 516 * The _PRW object must return a package, we are only interested in the 517 * first element 518 */ 519 ObjDesc = PkgDesc->Package.Elements[0]; 520 521 if (ObjDesc->Common.Type == ACPI_TYPE_INTEGER) 522 { 523 /* Use FADT-defined GPE device (from definition of _PRW) */ 524 525 TargetGpeDevice = AcpiGbl_FadtGpeDevice; 526 527 /* Integer is the GPE number in the FADT described GPE blocks */ 528 529 GpeNumber = (UINT32) ObjDesc->Integer.Value; 530 } 531 else if (ObjDesc->Common.Type == ACPI_TYPE_PACKAGE) 532 { 533 /* Package contains a GPE reference and GPE number within a GPE block */ 534 535 if ((ObjDesc->Package.Count < 2) || 536 ((ObjDesc->Package.Elements[0])->Common.Type != 537 ACPI_TYPE_LOCAL_REFERENCE) || 538 ((ObjDesc->Package.Elements[1])->Common.Type != 539 ACPI_TYPE_INTEGER)) 540 { 541 goto Cleanup; 542 } 543 544 /* Get GPE block reference and decode */ 545 546 TargetGpeDevice = ObjDesc->Package.Elements[0]->Reference.Node; 547 GpeNumber = (UINT32) ObjDesc->Package.Elements[1]->Integer.Value; 548 } 549 else 550 { 551 /* Unknown type, just ignore it */ 552 553 goto Cleanup; 554 } 555 556 /* 557 * Is this GPE within this block? 558 * 559 * TRUE if and only if these conditions are true: 560 * 1) The GPE devices match. 561 * 2) The GPE index(number) is within the range of the Gpe Block 562 * associated with the GPE device. 563 */ 564 if ((GpeDevice == TargetGpeDevice) && 565 (GpeNumber >= GpeBlock->BlockBaseNumber) && 566 (GpeNumber < GpeBlock->BlockBaseNumber + 567 (GpeBlock->RegisterCount * 8))) 568 { 569 GpeEventInfo = &GpeBlock->EventInfo[GpeNumber - 570 GpeBlock->BlockBaseNumber]; 571 572 /* Mark GPE for WAKE-ONLY but WAKE_DISABLED */ 573 574 GpeEventInfo->Flags &= ~(ACPI_GPE_WAKE_ENABLED | ACPI_GPE_RUN_ENABLED); 575 576 Status = AcpiEvSetGpeType (GpeEventInfo, ACPI_GPE_TYPE_WAKE); 577 if (ACPI_FAILURE (Status)) 578 { 579 goto Cleanup; 580 } 581 582 Status = AcpiEvUpdateGpeEnableMasks (GpeEventInfo, ACPI_GPE_DISABLE); 583 } 584 585Cleanup: 586 AcpiUtRemoveReference (PkgDesc); 587 return_ACPI_STATUS (AE_OK); 588} 589 590 591/******************************************************************************* 592 * 593 * FUNCTION: AcpiEvGetGpeXruptBlock 594 * 595 * PARAMETERS: InterruptNumber - Interrupt for a GPE block 596 * 597 * RETURN: A GPE interrupt block 598 * 599 * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt 600 * block per unique interrupt level used for GPEs. Should be 601 * called only when the GPE lists are semaphore locked and not 602 * subject to change. 603 * 604 ******************************************************************************/ 605 606static ACPI_GPE_XRUPT_INFO * 607AcpiEvGetGpeXruptBlock ( 608 UINT32 InterruptNumber) 609{ 610 ACPI_GPE_XRUPT_INFO *NextGpeXrupt; 611 ACPI_GPE_XRUPT_INFO *GpeXrupt; 612 ACPI_STATUS Status; 613 ACPI_CPU_FLAGS Flags; 614 615 616 ACPI_FUNCTION_TRACE (EvGetGpeXruptBlock); 617 618 619 /* No need for lock since we are not changing any list elements here */ 620 621 NextGpeXrupt = AcpiGbl_GpeXruptListHead; 622 while (NextGpeXrupt) 623 { 624 if (NextGpeXrupt->InterruptNumber == InterruptNumber) 625 { 626 return_PTR (NextGpeXrupt); 627 } 628 629 NextGpeXrupt = NextGpeXrupt->Next; 630 } 631 632 /* Not found, must allocate a new xrupt descriptor */ 633 634 GpeXrupt = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_XRUPT_INFO)); 635 if (!GpeXrupt) 636 { 637 return_PTR (NULL); 638 } 639 640 GpeXrupt->InterruptNumber = InterruptNumber; 641 642 /* Install new interrupt descriptor with spin lock */ 643 644 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 645 if (AcpiGbl_GpeXruptListHead) 646 { 647 NextGpeXrupt = AcpiGbl_GpeXruptListHead; 648 while (NextGpeXrupt->Next) 649 { 650 NextGpeXrupt = NextGpeXrupt->Next; 651 } 652 653 NextGpeXrupt->Next = GpeXrupt; 654 GpeXrupt->Previous = NextGpeXrupt; 655 } 656 else 657 { 658 AcpiGbl_GpeXruptListHead = GpeXrupt; 659 } 660 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 661 662 /* Install new interrupt handler if not SCI_INT */ 663 664 if (InterruptNumber != AcpiGbl_FADT.SciInterrupt) 665 { 666 Status = AcpiOsInstallInterruptHandler (InterruptNumber, 667 AcpiEvGpeXruptHandler, GpeXrupt); 668 if (ACPI_FAILURE (Status)) 669 { 670 ACPI_ERROR ((AE_INFO, 671 "Could not install GPE interrupt handler at level 0x%X", 672 InterruptNumber)); 673 return_PTR (NULL); 674 } 675 } 676 677 return_PTR (GpeXrupt); 678} 679 680 681/******************************************************************************* 682 * 683 * FUNCTION: AcpiEvDeleteGpeXrupt 684 * 685 * PARAMETERS: GpeXrupt - A GPE interrupt info block 686 * 687 * RETURN: Status 688 * 689 * DESCRIPTION: Remove and free a GpeXrupt block. Remove an associated 690 * interrupt handler if not the SCI interrupt. 691 * 692 ******************************************************************************/ 693 694static ACPI_STATUS 695AcpiEvDeleteGpeXrupt ( 696 ACPI_GPE_XRUPT_INFO *GpeXrupt) 697{ 698 ACPI_STATUS Status; 699 ACPI_CPU_FLAGS Flags; 700 701 702 ACPI_FUNCTION_TRACE (EvDeleteGpeXrupt); 703 704 705 /* We never want to remove the SCI interrupt handler */ 706 707 if (GpeXrupt->InterruptNumber == AcpiGbl_FADT.SciInterrupt) 708 { 709 GpeXrupt->GpeBlockListHead = NULL; 710 return_ACPI_STATUS (AE_OK); 711 } 712 713 /* Disable this interrupt */ 714 715 Status = AcpiOsRemoveInterruptHandler ( 716 GpeXrupt->InterruptNumber, AcpiEvGpeXruptHandler); 717 if (ACPI_FAILURE (Status)) 718 { 719 return_ACPI_STATUS (Status); 720 } 721 722 /* Unlink the interrupt block with lock */ 723 724 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 725 if (GpeXrupt->Previous) 726 { 727 GpeXrupt->Previous->Next = GpeXrupt->Next; 728 } 729 else 730 { 731 /* No previous, update list head */ 732 733 AcpiGbl_GpeXruptListHead = GpeXrupt->Next; 734 } 735 736 if (GpeXrupt->Next) 737 { 738 GpeXrupt->Next->Previous = GpeXrupt->Previous; 739 } 740 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 741 742 /* Free the block */ 743 744 ACPI_FREE (GpeXrupt); 745 return_ACPI_STATUS (AE_OK); 746} 747 748 749/******************************************************************************* 750 * 751 * FUNCTION: AcpiEvInstallGpeBlock 752 * 753 * PARAMETERS: GpeBlock - New GPE block 754 * InterruptNumber - Xrupt to be associated with this 755 * GPE block 756 * 757 * RETURN: Status 758 * 759 * DESCRIPTION: Install new GPE block with mutex support 760 * 761 ******************************************************************************/ 762 763static ACPI_STATUS 764AcpiEvInstallGpeBlock ( 765 ACPI_GPE_BLOCK_INFO *GpeBlock, 766 UINT32 InterruptNumber) 767{ 768 ACPI_GPE_BLOCK_INFO *NextGpeBlock; 769 ACPI_GPE_XRUPT_INFO *GpeXruptBlock; 770 ACPI_STATUS Status; 771 ACPI_CPU_FLAGS Flags; 772 773 774 ACPI_FUNCTION_TRACE (EvInstallGpeBlock); 775 776 777 Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); 778 if (ACPI_FAILURE (Status)) 779 { 780 return_ACPI_STATUS (Status); 781 } 782 783 GpeXruptBlock = AcpiEvGetGpeXruptBlock (InterruptNumber); 784 if (!GpeXruptBlock) 785 { 786 Status = AE_NO_MEMORY; 787 goto UnlockAndExit; 788 } 789 790 /* Install the new block at the end of the list with lock */ 791 792 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 793 if (GpeXruptBlock->GpeBlockListHead) 794 { 795 NextGpeBlock = GpeXruptBlock->GpeBlockListHead; 796 while (NextGpeBlock->Next) 797 { 798 NextGpeBlock = NextGpeBlock->Next; 799 } 800 801 NextGpeBlock->Next = GpeBlock; 802 GpeBlock->Previous = NextGpeBlock; 803 } 804 else 805 { 806 GpeXruptBlock->GpeBlockListHead = GpeBlock; 807 } 808 809 GpeBlock->XruptBlock = GpeXruptBlock; 810 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 811 812 813UnlockAndExit: 814 Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS); 815 return_ACPI_STATUS (Status); 816} 817 818 819/******************************************************************************* 820 * 821 * FUNCTION: AcpiEvDeleteGpeBlock 822 * 823 * PARAMETERS: GpeBlock - Existing GPE block 824 * 825 * RETURN: Status 826 * 827 * DESCRIPTION: Remove a GPE block 828 * 829 ******************************************************************************/ 830 831ACPI_STATUS 832AcpiEvDeleteGpeBlock ( 833 ACPI_GPE_BLOCK_INFO *GpeBlock) 834{ 835 ACPI_STATUS Status; 836 ACPI_CPU_FLAGS Flags; 837 838 839 ACPI_FUNCTION_TRACE (EvInstallGpeBlock); 840 841 842 Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); 843 if (ACPI_FAILURE (Status)) 844 { 845 return_ACPI_STATUS (Status); 846 } 847 848 /* Disable all GPEs in this block */ 849 850 Status = AcpiHwDisableGpeBlock (GpeBlock->XruptBlock, GpeBlock, NULL); 851 852 if (!GpeBlock->Previous && !GpeBlock->Next) 853 { 854 /* This is the last GpeBlock on this interrupt */ 855 856 Status = AcpiEvDeleteGpeXrupt (GpeBlock->XruptBlock); 857 if (ACPI_FAILURE (Status)) 858 { 859 goto UnlockAndExit; 860 } 861 } 862 else 863 { 864 /* Remove the block on this interrupt with lock */ 865 866 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 867 if (GpeBlock->Previous) 868 { 869 GpeBlock->Previous->Next = GpeBlock->Next; 870 } 871 else 872 { 873 GpeBlock->XruptBlock->GpeBlockListHead = GpeBlock->Next; 874 } 875 876 if (GpeBlock->Next) 877 { 878 GpeBlock->Next->Previous = GpeBlock->Previous; 879 } 880 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 881 } 882 883 AcpiCurrentGpeCount -= GpeBlock->RegisterCount * ACPI_GPE_REGISTER_WIDTH; 884 885 /* Free the GpeBlock */ 886 887 ACPI_FREE (GpeBlock->RegisterInfo); 888 ACPI_FREE (GpeBlock->EventInfo); 889 ACPI_FREE (GpeBlock); 890 891UnlockAndExit: 892 Status = AcpiUtReleaseMutex (ACPI_MTX_EVENTS); 893 return_ACPI_STATUS (Status); 894} 895 896 897/******************************************************************************* 898 * 899 * FUNCTION: AcpiEvCreateGpeInfoBlocks 900 * 901 * PARAMETERS: GpeBlock - New GPE block 902 * 903 * RETURN: Status 904 * 905 * DESCRIPTION: Create the RegisterInfo and EventInfo blocks for this GPE block 906 * 907 ******************************************************************************/ 908 909static ACPI_STATUS 910AcpiEvCreateGpeInfoBlocks ( 911 ACPI_GPE_BLOCK_INFO *GpeBlock) 912{ 913 ACPI_GPE_REGISTER_INFO *GpeRegisterInfo = NULL; 914 ACPI_GPE_EVENT_INFO *GpeEventInfo = NULL; 915 ACPI_GPE_EVENT_INFO *ThisEvent; 916 ACPI_GPE_REGISTER_INFO *ThisRegister; 917 UINT32 i; 918 UINT32 j; 919 ACPI_STATUS Status; 920 921 922 ACPI_FUNCTION_TRACE (EvCreateGpeInfoBlocks); 923 924 925 /* Allocate the GPE register information block */ 926 927 GpeRegisterInfo = ACPI_ALLOCATE_ZEROED ( 928 (ACPI_SIZE) GpeBlock->RegisterCount * 929 sizeof (ACPI_GPE_REGISTER_INFO)); 930 if (!GpeRegisterInfo) 931 { 932 ACPI_ERROR ((AE_INFO, 933 "Could not allocate the GpeRegisterInfo table")); 934 return_ACPI_STATUS (AE_NO_MEMORY); 935 } 936 937 /* 938 * Allocate the GPE EventInfo block. There are eight distinct GPEs 939 * per register. Initialization to zeros is sufficient. 940 */ 941 GpeEventInfo = ACPI_ALLOCATE_ZEROED ( 942 ((ACPI_SIZE) GpeBlock->RegisterCount * 943 ACPI_GPE_REGISTER_WIDTH) * 944 sizeof (ACPI_GPE_EVENT_INFO)); 945 if (!GpeEventInfo) 946 { 947 ACPI_ERROR ((AE_INFO, 948 "Could not allocate the GpeEventInfo table")); 949 Status = AE_NO_MEMORY; 950 goto ErrorExit; 951 } 952 953 /* Save the new Info arrays in the GPE block */ 954 955 GpeBlock->RegisterInfo = GpeRegisterInfo; 956 GpeBlock->EventInfo = GpeEventInfo; 957 958 /* 959 * Initialize the GPE Register and Event structures. A goal of these 960 * tables is to hide the fact that there are two separate GPE register 961 * sets in a given GPE hardware block, the status registers occupy the 962 * first half, and the enable registers occupy the second half. 963 */ 964 ThisRegister = GpeRegisterInfo; 965 ThisEvent = GpeEventInfo; 966 967 for (i = 0; i < GpeBlock->RegisterCount; i++) 968 { 969 /* Init the RegisterInfo for this GPE register (8 GPEs) */ 970 971 ThisRegister->BaseGpeNumber = (UINT8) (GpeBlock->BlockBaseNumber + 972 (i * ACPI_GPE_REGISTER_WIDTH)); 973 974 ThisRegister->StatusAddress.Address = 975 GpeBlock->BlockAddress.Address + i; 976 977 ThisRegister->EnableAddress.Address = 978 GpeBlock->BlockAddress.Address + i + GpeBlock->RegisterCount; 979 980 ThisRegister->StatusAddress.SpaceId = GpeBlock->BlockAddress.SpaceId; 981 ThisRegister->EnableAddress.SpaceId = GpeBlock->BlockAddress.SpaceId; 982 ThisRegister->StatusAddress.BitWidth = ACPI_GPE_REGISTER_WIDTH; 983 ThisRegister->EnableAddress.BitWidth = ACPI_GPE_REGISTER_WIDTH; 984 ThisRegister->StatusAddress.BitOffset = 0; 985 ThisRegister->EnableAddress.BitOffset = 0; 986 987 /* Init the EventInfo for each GPE within this register */ 988 989 for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) 990 { 991 ThisEvent->GpeNumber = (UINT8) (ThisRegister->BaseGpeNumber + j); 992 ThisEvent->RegisterInfo = ThisRegister; 993 ThisEvent++; 994 } 995 996 /* Disable all GPEs within this register */ 997 998 Status = AcpiHwWrite (0x00, &ThisRegister->EnableAddress); 999 if (ACPI_FAILURE (Status)) 1000 { 1001 goto ErrorExit; 1002 } 1003 1004 /* Clear any pending GPE events within this register */ 1005 1006 Status = AcpiHwWrite (0xFF, &ThisRegister->StatusAddress); 1007 if (ACPI_FAILURE (Status)) 1008 { 1009 goto ErrorExit; 1010 } 1011 1012 ThisRegister++; 1013 } 1014 1015 return_ACPI_STATUS (AE_OK); 1016 1017 1018ErrorExit: 1019 if (GpeRegisterInfo) 1020 { 1021 ACPI_FREE (GpeRegisterInfo); 1022 } 1023 if (GpeEventInfo) 1024 { 1025 ACPI_FREE (GpeEventInfo); 1026 } 1027 1028 return_ACPI_STATUS (Status); 1029} 1030 1031 1032/******************************************************************************* 1033 * 1034 * FUNCTION: AcpiEvCreateGpeBlock 1035 * 1036 * PARAMETERS: GpeDevice - Handle to the parent GPE block 1037 * GpeBlockAddress - Address and SpaceID 1038 * RegisterCount - Number of GPE register pairs in the block 1039 * GpeBlockBaseNumber - Starting GPE number for the block 1040 * InterruptNumber - H/W interrupt for the block 1041 * ReturnGpeBlock - Where the new block descriptor is returned 1042 * 1043 * RETURN: Status 1044 * 1045 * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within 1046 * the block are disabled at exit. 1047 * Note: Assumes namespace is locked. 1048 * 1049 ******************************************************************************/ 1050 1051ACPI_STATUS 1052AcpiEvCreateGpeBlock ( 1053 ACPI_NAMESPACE_NODE *GpeDevice, 1054 ACPI_GENERIC_ADDRESS *GpeBlockAddress, 1055 UINT32 RegisterCount, 1056 UINT8 GpeBlockBaseNumber, 1057 UINT32 InterruptNumber, 1058 ACPI_GPE_BLOCK_INFO **ReturnGpeBlock) 1059{ 1060 ACPI_STATUS Status; 1061 ACPI_GPE_BLOCK_INFO *GpeBlock; 1062 1063 1064 ACPI_FUNCTION_TRACE (EvCreateGpeBlock); 1065 1066 1067 if (!RegisterCount) 1068 { 1069 return_ACPI_STATUS (AE_OK); 1070 } 1071 1072 /* Allocate a new GPE block */ 1073 1074 GpeBlock = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_BLOCK_INFO)); 1075 if (!GpeBlock) 1076 { 1077 return_ACPI_STATUS (AE_NO_MEMORY); 1078 } 1079 1080 /* Initialize the new GPE block */ 1081 1082 GpeBlock->Node = GpeDevice; 1083 GpeBlock->RegisterCount = RegisterCount; 1084 GpeBlock->BlockBaseNumber = GpeBlockBaseNumber; 1085 1086 ACPI_MEMCPY (&GpeBlock->BlockAddress, GpeBlockAddress, 1087 sizeof (ACPI_GENERIC_ADDRESS)); 1088 1089 /* 1090 * Create the RegisterInfo and EventInfo sub-structures 1091 * Note: disables and clears all GPEs in the block 1092 */ 1093 Status = AcpiEvCreateGpeInfoBlocks (GpeBlock); 1094 if (ACPI_FAILURE (Status)) 1095 { 1096 ACPI_FREE (GpeBlock); 1097 return_ACPI_STATUS (Status); 1098 } 1099 1100 /* Install the new block in the global lists */ 1101 1102 Status = AcpiEvInstallGpeBlock (GpeBlock, InterruptNumber); 1103 if (ACPI_FAILURE (Status)) 1104 { 1105 ACPI_FREE (GpeBlock); 1106 return_ACPI_STATUS (Status); 1107 } 1108 1109 /* Find all GPE methods (_Lxx, _Exx) for this block */ 1110 1111 Status = AcpiNsWalkNamespace (ACPI_TYPE_METHOD, GpeDevice, 1112 ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
|
1196 } 1197 1198 /* 1199 * Enable all GPEs in this block that have these attributes: 1200 * 1) are "runtime" or "run/wake" GPEs, and 1201 * 2) have a corresponding _Lxx or _Exx method 1202 * 1203 * Any other GPEs within this block must be enabled via the 1204 * AcpiEnableGpe() external interface. 1205 */ 1206 WakeGpeCount = 0; 1207 GpeEnabledCount = 0; 1208 1209 for (i = 0; i < GpeBlock->RegisterCount; i++) 1210 { 1211 for (j = 0; j < 8; j++) 1212 { 1213 /* Get the info block for this particular GPE */ 1214 1215 GpeEventInfo = &GpeBlock->EventInfo[((ACPI_SIZE) i * 1216 ACPI_GPE_REGISTER_WIDTH) + j]; 1217 1218 if (((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) == 1219 ACPI_GPE_DISPATCH_METHOD) && 1220 (GpeEventInfo->Flags & ACPI_GPE_TYPE_RUNTIME)) 1221 { 1222 GpeEnabledCount++; 1223 } 1224 1225 if (GpeEventInfo->Flags & ACPI_GPE_TYPE_WAKE) 1226 { 1227 WakeGpeCount++; 1228 } 1229 } 1230 } 1231 1232 ACPI_DEBUG_PRINT ((ACPI_DB_INIT, 1233 "Found %u Wake, Enabled %u Runtime GPEs in this block\n", 1234 WakeGpeCount, GpeEnabledCount)); 1235 1236 /* Enable all valid runtime GPEs found above */ 1237 1238 Status = AcpiHwEnableRuntimeGpeBlock (NULL, GpeBlock, NULL); 1239 if (ACPI_FAILURE (Status)) 1240 { 1241 ACPI_ERROR ((AE_INFO, "Could not enable GPEs in GpeBlock %p", 1242 GpeBlock)); 1243 } 1244 1245 return_ACPI_STATUS (Status); 1246} 1247 1248 1249/******************************************************************************* 1250 * 1251 * FUNCTION: AcpiEvGpeInitialize 1252 * 1253 * PARAMETERS: None 1254 * 1255 * RETURN: Status 1256 * 1257 * DESCRIPTION: Initialize the GPE data structures 1258 * 1259 ******************************************************************************/ 1260 1261ACPI_STATUS 1262AcpiEvGpeInitialize ( 1263 void) 1264{ 1265 UINT32 RegisterCount0 = 0; 1266 UINT32 RegisterCount1 = 0; 1267 UINT32 GpeNumberMax = 0; 1268 ACPI_STATUS Status; 1269 1270 1271 ACPI_FUNCTION_TRACE (EvGpeInitialize); 1272 1273 1274 Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); 1275 if (ACPI_FAILURE (Status)) 1276 { 1277 return_ACPI_STATUS (Status); 1278 } 1279 1280 /* 1281 * Initialize the GPE Block(s) defined in the FADT 1282 * 1283 * Why the GPE register block lengths are divided by 2: From the ACPI 1284 * Spec, section "General-Purpose Event Registers", we have: 1285 * 1286 * "Each register block contains two registers of equal length 1287 * GPEx_STS and GPEx_EN (where x is 0 or 1). The length of the 1288 * GPE0_STS and GPE0_EN registers is equal to half the GPE0_LEN 1289 * The length of the GPE1_STS and GPE1_EN registers is equal to 1290 * half the GPE1_LEN. If a generic register block is not supported 1291 * then its respective block pointer and block length values in the 1292 * FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need 1293 * to be the same size." 1294 */ 1295 1296 /* 1297 * Determine the maximum GPE number for this machine. 1298 * 1299 * Note: both GPE0 and GPE1 are optional, and either can exist without 1300 * the other. 1301 * 1302 * If EITHER the register length OR the block address are zero, then that 1303 * particular block is not supported. 1304 */ 1305 if (AcpiGbl_FADT.Gpe0BlockLength && 1306 AcpiGbl_FADT.XGpe0Block.Address) 1307 { 1308 /* GPE block 0 exists (has both length and address > 0) */ 1309 1310 RegisterCount0 = (UINT16) (AcpiGbl_FADT.Gpe0BlockLength / 2); 1311 1312 GpeNumberMax = (RegisterCount0 * ACPI_GPE_REGISTER_WIDTH) - 1; 1313 1314 /* Install GPE Block 0 */ 1315 1316 Status = AcpiEvCreateGpeBlock (AcpiGbl_FadtGpeDevice, 1317 &AcpiGbl_FADT.XGpe0Block, RegisterCount0, 0, 1318 AcpiGbl_FADT.SciInterrupt, &AcpiGbl_GpeFadtBlocks[0]); 1319 1320 if (ACPI_FAILURE (Status)) 1321 { 1322 ACPI_EXCEPTION ((AE_INFO, Status, 1323 "Could not create GPE Block 0")); 1324 } 1325 } 1326 1327 if (AcpiGbl_FADT.Gpe1BlockLength && 1328 AcpiGbl_FADT.XGpe1Block.Address) 1329 { 1330 /* GPE block 1 exists (has both length and address > 0) */ 1331 1332 RegisterCount1 = (UINT16) (AcpiGbl_FADT.Gpe1BlockLength / 2); 1333 1334 /* Check for GPE0/GPE1 overlap (if both banks exist) */ 1335 1336 if ((RegisterCount0) && 1337 (GpeNumberMax >= AcpiGbl_FADT.Gpe1Base)) 1338 { 1339 ACPI_ERROR ((AE_INFO, 1340 "GPE0 block (GPE 0 to %d) overlaps the GPE1 block " 1341 "(GPE %d to %d) - Ignoring GPE1", 1342 GpeNumberMax, AcpiGbl_FADT.Gpe1Base, 1343 AcpiGbl_FADT.Gpe1Base + 1344 ((RegisterCount1 * ACPI_GPE_REGISTER_WIDTH) - 1))); 1345 1346 /* Ignore GPE1 block by setting the register count to zero */ 1347 1348 RegisterCount1 = 0; 1349 } 1350 else 1351 { 1352 /* Install GPE Block 1 */ 1353 1354 Status = AcpiEvCreateGpeBlock (AcpiGbl_FadtGpeDevice, 1355 &AcpiGbl_FADT.XGpe1Block, RegisterCount1, 1356 AcpiGbl_FADT.Gpe1Base, 1357 AcpiGbl_FADT.SciInterrupt, &AcpiGbl_GpeFadtBlocks[1]); 1358 1359 if (ACPI_FAILURE (Status)) 1360 { 1361 ACPI_EXCEPTION ((AE_INFO, Status, 1362 "Could not create GPE Block 1")); 1363 } 1364 1365 /* 1366 * GPE0 and GPE1 do not have to be contiguous in the GPE number 1367 * space. However, GPE0 always starts at GPE number zero. 1368 */ 1369 GpeNumberMax = AcpiGbl_FADT.Gpe1Base + 1370 ((RegisterCount1 * ACPI_GPE_REGISTER_WIDTH) - 1); 1371 } 1372 } 1373 1374 /* Exit if there are no GPE registers */ 1375 1376 if ((RegisterCount0 + RegisterCount1) == 0) 1377 { 1378 /* GPEs are not required by ACPI, this is OK */ 1379 1380 ACPI_DEBUG_PRINT ((ACPI_DB_INIT, 1381 "There are no GPE blocks defined in the FADT\n")); 1382 Status = AE_OK; 1383 goto Cleanup; 1384 } 1385 1386 /* Check for Max GPE number out-of-range */ 1387 1388 if (GpeNumberMax > ACPI_GPE_MAX) 1389 { 1390 ACPI_ERROR ((AE_INFO, 1391 "Maximum GPE number from FADT is too large: 0x%X", 1392 GpeNumberMax)); 1393 Status = AE_BAD_VALUE; 1394 goto Cleanup; 1395 } 1396 1397Cleanup: 1398 (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); 1399 return_ACPI_STATUS (AE_OK); 1400} 1401 1402
|