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