/****************************************************************************** * * Module Name: evxfgpe - External Interfaces for General Purpose Events (GPEs) * *****************************************************************************/ /* * Copyright (C) 2000 - 2016, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * substantially similar to the "NO WARRANTY" disclaimer below * ("Disclaimer") and any redistribution must be conditioned upon * including a substantially similar Disclaimer requirement for further * binary redistribution. * 3. Neither the names of the above-listed copyright holders nor the names * of any contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. */ #define EXPORT_ACPI_INTERFACES #include "acpi.h" #include "accommon.h" #include "acevents.h" #include "acnamesp.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME ("evxfgpe") #if (!ACPI_REDUCED_HARDWARE) /* Entire module */ /******************************************************************************* * * FUNCTION: AcpiUpdateAllGpes * * PARAMETERS: None * * RETURN: Status * * DESCRIPTION: Complete GPE initialization and enable all GPEs that have * associated _Lxx or _Exx methods and are not pointed to by any * device _PRW methods (this indicates that these GPEs are * generally intended for system or device wakeup. Such GPEs * have to be enabled directly when the devices whose _PRW * methods point to them are set up for wakeup signaling.) * * NOTE: Should be called after any GPEs are added to the system. Primarily, * after the system _PRW methods have been run, but also after a GPE Block * Device has been added or if any new GPE methods have been added via a * dynamic table load. * ******************************************************************************/ ACPI_STATUS AcpiUpdateAllGpes ( void) { ACPI_STATUS Status; ACPI_FUNCTION_TRACE (AcpiUpdateAllGpes); Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } if (AcpiGbl_AllGpesInitialized) { goto UnlockAndExit; } Status = AcpiEvWalkGpeList (AcpiEvInitializeGpeBlock, NULL); if (ACPI_SUCCESS (Status)) { AcpiGbl_AllGpesInitialized = TRUE; } UnlockAndExit: (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); return_ACPI_STATUS (Status); } ACPI_EXPORT_SYMBOL (AcpiUpdateAllGpes) /******************************************************************************* * * FUNCTION: AcpiEnableGpe * * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 * GpeNumber - GPE level within the GPE block * * RETURN: Status * * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is * hardware-enabled. * ******************************************************************************/ ACPI_STATUS AcpiEnableGpe ( ACPI_HANDLE GpeDevice, UINT32 GpeNumber) { ACPI_STATUS Status = AE_BAD_PARAMETER; ACPI_GPE_EVENT_INFO *GpeEventInfo; ACPI_CPU_FLAGS Flags; ACPI_FUNCTION_TRACE (AcpiEnableGpe); Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); /* * Ensure that we have a valid GPE number and that there is some way * of handling the GPE (handler or a GPE method). In other words, we * won't allow a valid GPE to be enabled if there is no way to handle it. */ GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); if (GpeEventInfo) { if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) != ACPI_GPE_DISPATCH_NONE) { Status = AcpiEvAddGpeReference (GpeEventInfo); } else { Status = AE_NO_HANDLER; } } AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); return_ACPI_STATUS (Status); } ACPI_EXPORT_SYMBOL (AcpiEnableGpe) /******************************************************************************* * * FUNCTION: AcpiDisableGpe * * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 * GpeNumber - GPE level within the GPE block * * RETURN: Status * * DESCRIPTION: Remove a reference to a GPE. When the last reference is * removed, only then is the GPE disabled (for runtime GPEs), or * the GPE mask bit disabled (for wake GPEs) * ******************************************************************************/ ACPI_STATUS AcpiDisableGpe ( ACPI_HANDLE GpeDevice, UINT32 GpeNumber) { ACPI_STATUS Status = AE_BAD_PARAMETER; ACPI_GPE_EVENT_INFO *GpeEventInfo; ACPI_CPU_FLAGS Flags; ACPI_FUNCTION_TRACE (AcpiDisableGpe); Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); /* Ensure that we have a valid GPE number */ GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); if (GpeEventInfo) { Status = AcpiEvRemoveGpeReference (GpeEventInfo); } AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); return_ACPI_STATUS (Status); } ACPI_EXPORT_SYMBOL (AcpiDisableGpe) /******************************************************************************* * * FUNCTION: AcpiSetGpe * * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 * GpeNumber - GPE level within the GPE block * Action - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE * * RETURN: Status * * DESCRIPTION: Enable or disable an individual GPE. This function bypasses * the reference count mechanism used in the AcpiEnableGpe(), * AcpiDisableGpe() interfaces. * This API is typically used by the GPE raw handler mode driver * to switch between the polling mode and the interrupt mode after * the driver has enabled the GPE. * The APIs should be invoked in this order: * AcpiEnableGpe() <- Ensure the reference count > 0 * AcpiSetGpe(ACPI_GPE_DISABLE) <- Enter polling mode * AcpiSetGpe(ACPI_GPE_ENABLE) <- Leave polling mode * AcpiDisableGpe() <- Decrease the reference count * * Note: If a GPE is shared by 2 silicon components, then both the drivers * should support GPE polling mode or disabling the GPE for long period * for one driver may break the other. So use it with care since all * firmware _Lxx/_Exx handlers currently rely on the GPE interrupt mode. * ******************************************************************************/ ACPI_STATUS AcpiSetGpe ( ACPI_HANDLE GpeDevice, UINT32 GpeNumber, UINT8 Action) { ACPI_GPE_EVENT_INFO *GpeEventInfo; ACPI_STATUS Status; ACPI_CPU_FLAGS Flags; ACPI_FUNCTION_TRACE (AcpiSetGpe); Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); /* Ensure that we have a valid GPE number */ GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); if (!GpeEventInfo) { Status = AE_BAD_PARAMETER; goto UnlockAndExit; } /* Perform the action */ switch (Action) { case ACPI_GPE_ENABLE: Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_ENABLE); break; case ACPI_GPE_DISABLE: Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE); break; default: Status = AE_BAD_PARAMETER; break; } UnlockAndExit: AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); return_ACPI_STATUS (Status); } ACPI_EXPORT_SYMBOL (AcpiSetGpe) /******************************************************************************* * * FUNCTION: AcpiMarkGpeForWake * * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 * GpeNumber - GPE level within the GPE block * * RETURN: Status * * DESCRIPTION: Mark a GPE as having the ability to wake the system. Simply * sets the ACPI_GPE_CAN_WAKE flag. * * Some potential callers of AcpiSetupGpeForWake may know in advance that * there won't be any notify handlers installed for device wake notifications * from the given GPE (one example is a button GPE in Linux). For these cases, * AcpiMarkGpeForWake should be used instead of AcpiSetupGpeForWake. * This will set the ACPI_GPE_CAN_WAKE flag for the GPE without trying to * setup implicit wake notification for it (since there's no handler method). * ******************************************************************************/ ACPI_STATUS AcpiMarkGpeForWake ( ACPI_HANDLE GpeDevice, UINT32 GpeNumber) { ACPI_GPE_EVENT_INFO *GpeEventInfo; ACPI_STATUS Status = AE_BAD_PARAMETER; ACPI_CPU_FLAGS Flags; ACPI_FUNCTION_TRACE (AcpiMarkGpeForWake); Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); /* Ensure that we have a valid GPE number */ GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); if (GpeEventInfo) { /* Mark the GPE as a possible wake event */ GpeEventInfo->Flags |= ACPI_GPE_CAN_WAKE; Status = AE_OK; } AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); return_ACPI_STATUS (Status); } ACPI_EXPORT_SYMBOL (AcpiMarkGpeForWake) /******************************************************************************* * * FUNCTION: AcpiSetupGpeForWake * * PARAMETERS: WakeDevice - Device associated with the GPE (via _PRW) * GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 * GpeNumber - GPE level within the GPE block * * RETURN: Status * * DESCRIPTION: Mark a GPE as having the ability to wake the system. This * interface is intended to be used as the host executes the * _PRW methods (Power Resources for Wake) in the system tables. * Each _PRW appears under a Device Object (The WakeDevice), and * contains the info for the wake GPE associated with the * WakeDevice. * ******************************************************************************/ ACPI_STATUS AcpiSetupGpeForWake ( ACPI_HANDLE WakeDevice, ACPI_HANDLE GpeDevice, UINT32 GpeNumber) { ACPI_STATUS Status; ACPI_GPE_EVENT_INFO *GpeEventInfo; ACPI_NAMESPACE_NODE *DeviceNode; ACPI_GPE_NOTIFY_INFO *Notify; ACPI_GPE_NOTIFY_INFO *NewNotify; ACPI_CPU_FLAGS Flags; ACPI_FUNCTION_TRACE (AcpiSetupGpeForWake); /* Parameter Validation */ if (!WakeDevice) { /* * By forcing WakeDevice to be valid, we automatically enable the * implicit notify feature on all hosts. */ return_ACPI_STATUS (AE_BAD_PARAMETER); } /* Handle root object case */ if (WakeDevice == ACPI_ROOT_OBJECT) { DeviceNode = AcpiGbl_RootNode; } else { DeviceNode = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, WakeDevice); } /* Validate WakeDevice is of type Device */ if (DeviceNode->Type != ACPI_TYPE_DEVICE) { return_ACPI_STATUS (AE_BAD_PARAMETER); } /* * Allocate a new notify object up front, in case it is needed. * Memory allocation while holding a spinlock is a big no-no * on some hosts. */ NewNotify = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_NOTIFY_INFO)); if (!NewNotify) { return_ACPI_STATUS (AE_NO_MEMORY); } Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); /* Ensure that we have a valid GPE number */ GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); if (!GpeEventInfo) { Status = AE_BAD_PARAMETER; goto UnlockAndExit; } /* * If there is no method or handler for this GPE, then the * WakeDevice will be notified whenever this GPE fires. This is * known as an "implicit notify". Note: The GPE is assumed to be * level-triggered (for windows compatibility). */ if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == ACPI_GPE_DISPATCH_NONE) { /* * This is the first device for implicit notify on this GPE. * Just set the flags here, and enter the NOTIFY block below. */ GpeEventInfo->Flags = (ACPI_GPE_DISPATCH_NOTIFY | ACPI_GPE_LEVEL_TRIGGERED); } /* * If we already have an implicit notify on this GPE, add * this device to the notify list. */ if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == ACPI_GPE_DISPATCH_NOTIFY) { /* Ensure that the device is not already in the list */ Notify = GpeEventInfo->Dispatch.NotifyList; while (Notify) { if (Notify->DeviceNode == DeviceNode) { Status = AE_ALREADY_EXISTS; goto UnlockAndExit; } Notify = Notify->Next; } /* Add this device to the notify list for this GPE */ NewNotify->DeviceNode = DeviceNode; NewNotify->Next = GpeEventInfo->Dispatch.NotifyList; GpeEventInfo->Dispatch.NotifyList = NewNotify; NewNotify = NULL; } /* Mark the GPE as a possible wake event */ GpeEventInfo->Flags |= ACPI_GPE_CAN_WAKE; Status = AE_OK; UnlockAndExit: AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); /* Delete the notify object if it was not used above */ if (NewNotify) { ACPI_FREE (NewNotify); } return_ACPI_STATUS (Status); } ACPI_EXPORT_SYMBOL (AcpiSetupGpeForWake) /******************************************************************************* * * FUNCTION: AcpiSetGpeWakeMask * * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 * GpeNumber - GPE level within the GPE block * Action - Enable or Disable * * RETURN: Status * * DESCRIPTION: Set or clear the GPE's wakeup enable mask bit. The GPE must * already be marked as a WAKE GPE. * ******************************************************************************/ ACPI_STATUS AcpiSetGpeWakeMask ( ACPI_HANDLE GpeDevice, UINT32 GpeNumber, UINT8 Action) { ACPI_STATUS Status = AE_OK; ACPI_GPE_EVENT_INFO *GpeEventInfo; ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; ACPI_CPU_FLAGS Flags; UINT32 RegisterBit; ACPI_FUNCTION_TRACE (AcpiSetGpeWakeMask); Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); /* * Ensure that we have a valid GPE number and that this GPE is in * fact a wake GPE */ GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); if (!GpeEventInfo) { Status = AE_BAD_PARAMETER; goto UnlockAndExit; } if (!(GpeEventInfo->Flags & ACPI_GPE_CAN_WAKE)) { Status = AE_TYPE; goto UnlockAndExit; } GpeRegisterInfo = GpeEventInfo->RegisterInfo; if (!GpeRegisterInfo) { Status = AE_NOT_EXIST; goto UnlockAndExit; } RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo); /* Perform the action */ switch (Action) { case ACPI_GPE_ENABLE: ACPI_SET_BIT (GpeRegisterInfo->EnableForWake, (UINT8) RegisterBit); break; case ACPI_GPE_DISABLE: ACPI_CLEAR_BIT (GpeRegisterInfo->EnableForWake, (UINT8) RegisterBit); break; default: ACPI_ERROR ((AE_INFO, "%u, Invalid action", Action)); Status = AE_BAD_PARAMETER; break; } UnlockAndExit: AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); return_ACPI_STATUS (Status); } ACPI_EXPORT_SYMBOL (AcpiSetGpeWakeMask) /******************************************************************************* * * FUNCTION: AcpiClearGpe * * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 * GpeNumber - GPE level within the GPE block * * RETURN: Status * * DESCRIPTION: Clear an ACPI event (general purpose) * ******************************************************************************/ ACPI_STATUS AcpiClearGpe ( ACPI_HANDLE GpeDevice, UINT32 GpeNumber) { ACPI_STATUS Status = AE_OK; ACPI_GPE_EVENT_INFO *GpeEventInfo; ACPI_CPU_FLAGS Flags; ACPI_FUNCTION_TRACE (AcpiClearGpe); Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); /* Ensure that we have a valid GPE number */ GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); if (!GpeEventInfo) { Status = AE_BAD_PARAMETER; goto UnlockAndExit; } Status = AcpiHwClearGpe (GpeEventInfo); UnlockAndExit: AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); return_ACPI_STATUS (Status); } ACPI_EXPORT_SYMBOL (AcpiClearGpe) /******************************************************************************* * * FUNCTION: AcpiGetGpeStatus * * PARAMETERS: GpeDevice - Parent GPE Device. NULL for GPE0/GPE1 * GpeNumber - GPE level within the GPE block * EventStatus - Where the current status of the event * will be returned * * RETURN: Status * * DESCRIPTION: Get the current status of a GPE (signalled/not_signalled) * ******************************************************************************/ ACPI_STATUS AcpiGetGpeStatus ( ACPI_HANDLE GpeDevice, UINT32 GpeNumber, ACPI_EVENT_STATUS *EventStatus) { ACPI_STATUS Status = AE_OK; ACPI_GPE_EVENT_INFO *GpeEventInfo; ACPI_CPU_FLAGS Flags; ACPI_FUNCTION_TRACE (AcpiGetGpeStatus); Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); /* Ensure that we have a valid GPE number */ GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); if (!GpeEventInfo) { Status = AE_BAD_PARAMETER; goto UnlockAndExit; } /* Obtain status on the requested GPE number */ Status = AcpiHwGetGpeStatus (GpeEventInfo, EventStatus); UnlockAndExit: AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); return_ACPI_STATUS (Status); } ACPI_EXPORT_SYMBOL (AcpiGetGpeStatus) /******************************************************************************* * * FUNCTION: AcpiFinishGpe * * PARAMETERS: GpeDevice - Namespace node for the GPE Block * (NULL for FADT defined GPEs) * GpeNumber - GPE level within the GPE block * * RETURN: Status * * DESCRIPTION: Clear and conditionally reenable a GPE. This completes the GPE * processing. Intended for use by asynchronous host-installed * GPE handlers. The GPE is only reenabled if the EnableForRun bit * is set in the GPE info. * ******************************************************************************/ ACPI_STATUS AcpiFinishGpe ( ACPI_HANDLE GpeDevice, UINT32 GpeNumber) { ACPI_GPE_EVENT_INFO *GpeEventInfo; ACPI_STATUS Status; ACPI_CPU_FLAGS Flags; ACPI_FUNCTION_TRACE (AcpiFinishGpe); Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); /* Ensure that we have a valid GPE number */ GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); if (!GpeEventInfo) { Status = AE_BAD_PARAMETER; goto UnlockAndExit; } Status = AcpiEvFinishGpe (GpeEventInfo); UnlockAndExit: AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); return_ACPI_STATUS (Status); } ACPI_EXPORT_SYMBOL (AcpiFinishGpe) /****************************************************************************** * * FUNCTION: AcpiDisableAllGpes * * PARAMETERS: None * * RETURN: Status * * DESCRIPTION: Disable and clear all GPEs in all GPE blocks * ******************************************************************************/ ACPI_STATUS AcpiDisableAllGpes ( void) { ACPI_STATUS Status; ACPI_FUNCTION_TRACE (AcpiDisableAllGpes); Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } Status = AcpiHwDisableAllGpes (); (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); return_ACPI_STATUS (Status); } ACPI_EXPORT_SYMBOL (AcpiDisableAllGpes) /****************************************************************************** * * FUNCTION: AcpiEnableAllRuntimeGpes * * PARAMETERS: None * * RETURN: Status * * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks * ******************************************************************************/ ACPI_STATUS AcpiEnableAllRuntimeGpes ( void) { ACPI_STATUS Status; ACPI_FUNCTION_TRACE (AcpiEnableAllRuntimeGpes); Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } Status = AcpiHwEnableAllRuntimeGpes (); (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); return_ACPI_STATUS (Status); } ACPI_EXPORT_SYMBOL (AcpiEnableAllRuntimeGpes) /****************************************************************************** * * FUNCTION: AcpiEnableAllWakeupGpes * * PARAMETERS: None * * RETURN: Status * * DESCRIPTION: Enable all "wakeup" GPEs and disable all of the other GPEs, in * all GPE blocks. * ******************************************************************************/ ACPI_STATUS AcpiEnableAllWakeupGpes ( void) { ACPI_STATUS Status; ACPI_FUNCTION_TRACE (AcpiEnableAllWakeupGpes); Status = AcpiUtAcquireMutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } Status = AcpiHwEnableAllWakeupGpes (); (void) AcpiUtReleaseMutex (ACPI_MTX_EVENTS); return_ACPI_STATUS (Status); } ACPI_EXPORT_SYMBOL (AcpiEnableAllWakeupGpes) /******************************************************************************* * * FUNCTION: AcpiInstallGpeBlock * * PARAMETERS: GpeDevice - Handle to the parent GPE Block Device * GpeBlockAddress - Address and SpaceID * RegisterCount - Number of GPE register pairs in the block * InterruptNumber - H/W interrupt for the block * * RETURN: Status * * DESCRIPTION: Create and Install a block of GPE registers. The GPEs are not * enabled here. * ******************************************************************************/ ACPI_STATUS AcpiInstallGpeBlock ( ACPI_HANDLE GpeDevice, ACPI_GENERIC_ADDRESS *GpeBlockAddress, UINT32 RegisterCount, UINT32 InterruptNumber) { ACPI_STATUS Status; ACPI_OPERAND_OBJECT *ObjDesc; ACPI_NAMESPACE_NODE *Node; ACPI_GPE_BLOCK_INFO *GpeBlock; ACPI_FUNCTION_TRACE (AcpiInstallGpeBlock); if ((!GpeDevice) || (!GpeBlockAddress) || (!RegisterCount)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } Node = AcpiNsValidateHandle (GpeDevice); if (!Node) { Status = AE_BAD_PARAMETER; goto UnlockAndExit; } /* Validate the parent device */ if (Node->Type != ACPI_TYPE_DEVICE) { Status = AE_TYPE; goto UnlockAndExit; } if (Node->Object) { Status = AE_ALREADY_EXISTS; goto UnlockAndExit; } /* * For user-installed GPE Block Devices, the GpeBlockBaseNumber * is always zero */ Status = AcpiEvCreateGpeBlock (Node, GpeBlockAddress->Address, GpeBlockAddress->SpaceId, RegisterCount, 0, InterruptNumber, &GpeBlock); if (ACPI_FAILURE (Status)) { goto UnlockAndExit; } /* Install block in the DeviceObject attached to the node */ ObjDesc = AcpiNsGetAttachedObject (Node); if (!ObjDesc) { /* * No object, create a new one (Device nodes do not always have * an attached object) */ ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_DEVICE); if (!ObjDesc) { Status = AE_NO_MEMORY; goto UnlockAndExit; } Status = AcpiNsAttachObject (Node, ObjDesc, ACPI_TYPE_DEVICE); /* Remove local reference to the object */ AcpiUtRemoveReference (ObjDesc); if (ACPI_FAILURE (Status)) { goto UnlockAndExit; } } /* Now install the GPE block in the DeviceObject */ ObjDesc->Device.GpeBlock = GpeBlock; UnlockAndExit: (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (Status); } ACPI_EXPORT_SYMBOL (AcpiInstallGpeBlock) /******************************************************************************* * * FUNCTION: AcpiRemoveGpeBlock * * PARAMETERS: GpeDevice - Handle to the parent GPE Block Device * * RETURN: Status * * DESCRIPTION: Remove a previously installed block of GPE registers * ******************************************************************************/ ACPI_STATUS AcpiRemoveGpeBlock ( ACPI_HANDLE GpeDevice) { ACPI_OPERAND_OBJECT *ObjDesc; ACPI_STATUS Status; ACPI_NAMESPACE_NODE *Node; ACPI_FUNCTION_TRACE (AcpiRemoveGpeBlock); if (!GpeDevice) { return_ACPI_STATUS (AE_BAD_PARAMETER); } Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } Node = AcpiNsValidateHandle (GpeDevice); if (!Node) { Status = AE_BAD_PARAMETER; goto UnlockAndExit; } /* Validate the parent device */ if (Node->Type != ACPI_TYPE_DEVICE) { Status = AE_TYPE; goto UnlockAndExit; } /* Get the DeviceObject attached to the node */ ObjDesc = AcpiNsGetAttachedObject (Node); if (!ObjDesc || !ObjDesc->Device.GpeBlock) { return_ACPI_STATUS (AE_NULL_OBJECT); } /* Delete the GPE block (but not the DeviceObject) */ Status = AcpiEvDeleteGpeBlock (ObjDesc->Device.GpeBlock); if (ACPI_SUCCESS (Status)) { ObjDesc->Device.GpeBlock = NULL; } UnlockAndExit: (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (Status); } ACPI_EXPORT_SYMBOL (AcpiRemoveGpeBlock) /******************************************************************************* * * FUNCTION: AcpiGetGpeDevice * * PARAMETERS: Index - System GPE index (0-CurrentGpeCount) * GpeDevice - Where the parent GPE Device is returned * * RETURN: Status * * DESCRIPTION: Obtain the GPE device associated with the input index. A NULL * gpe device indicates that the gpe number is contained in one of * the FADT-defined gpe blocks. Otherwise, the GPE block device. * ******************************************************************************/ ACPI_STATUS AcpiGetGpeDevice ( UINT32 Index, ACPI_HANDLE *GpeDevice) { ACPI_GPE_DEVICE_INFO Info; ACPI_STATUS Status; ACPI_FUNCTION_TRACE (AcpiGetGpeDevice); if (!GpeDevice) { return_ACPI_STATUS (AE_BAD_PARAMETER); } if (Index >= AcpiCurrentGpeCount) { return_ACPI_STATUS (AE_NOT_EXIST); } /* Setup and walk the GPE list */ Info.Index = Index; Info.Status = AE_NOT_EXIST; Info.GpeDevice = NULL; Info.NextBlockBaseIndex = 0; Status = AcpiEvWalkGpeList (AcpiEvGetGpeDevice, &Info); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } *GpeDevice = ACPI_CAST_PTR (ACPI_HANDLE, Info.GpeDevice); return_ACPI_STATUS (Info.Status); } ACPI_EXPORT_SYMBOL (AcpiGetGpeDevice) #endif /* !ACPI_REDUCED_HARDWARE */