/******************************************************************************1*2* Module Name: evxfgpe - External Interfaces for General Purpose Events (GPEs)3*4*****************************************************************************/56/*7* Copyright (C) 2000 - 2011, Intel Corp.8* All rights reserved.9*10* Redistribution and use in source and binary forms, with or without11* modification, are permitted provided that the following conditions12* are met:13* 1. Redistributions of source code must retain the above copyright14* notice, this list of conditions, and the following disclaimer,15* without modification.16* 2. Redistributions in binary form must reproduce at minimum a disclaimer17* substantially similar to the "NO WARRANTY" disclaimer below18* ("Disclaimer") and any redistribution must be conditioned upon19* including a substantially similar Disclaimer requirement for further20* binary redistribution.21* 3. Neither the names of the above-listed copyright holders nor the names22* of any contributors may be used to endorse or promote products derived23* from this software without specific prior written permission.24*25* Alternatively, this software may be distributed under the terms of the26* GNU General Public License ("GPL") version 2 as published by the Free27* Software Foundation.28*29* NO WARRANTY30* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS31* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT32* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR33* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT34* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL35* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS36* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)37* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,38* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING39* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE40* POSSIBILITY OF SUCH DAMAGES.41*/4243#include <acpi/acpi.h>44#include "accommon.h"45#include "acevents.h"46#include "acnamesp.h"4748#define _COMPONENT ACPI_EVENTS49ACPI_MODULE_NAME("evxfgpe")5051/******************************************************************************52*53* FUNCTION: acpi_update_all_gpes54*55* PARAMETERS: None56*57* RETURN: Status58*59* DESCRIPTION: Complete GPE initialization and enable all GPEs that have60* associated _Lxx or _Exx methods and are not pointed to by any61* device _PRW methods (this indicates that these GPEs are62* generally intended for system or device wakeup. Such GPEs63* have to be enabled directly when the devices whose _PRW64* methods point to them are set up for wakeup signaling.)65*66* NOTE: Should be called after any GPEs are added to the system. Primarily,67* after the system _PRW methods have been run, but also after a GPE Block68* Device has been added or if any new GPE methods have been added via a69* dynamic table load.70*71******************************************************************************/7273acpi_status acpi_update_all_gpes(void)74{75acpi_status status;7677ACPI_FUNCTION_TRACE(acpi_update_all_gpes);7879status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);80if (ACPI_FAILURE(status)) {81return_ACPI_STATUS(status);82}8384if (acpi_gbl_all_gpes_initialized) {85goto unlock_and_exit;86}8788status = acpi_ev_walk_gpe_list(acpi_ev_initialize_gpe_block, NULL);89if (ACPI_SUCCESS(status)) {90acpi_gbl_all_gpes_initialized = TRUE;91}9293unlock_and_exit:94(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);9596return_ACPI_STATUS(status);97}9899ACPI_EXPORT_SYMBOL(acpi_update_all_gpes)100101/*******************************************************************************102*103* FUNCTION: acpi_enable_gpe104*105* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1106* gpe_number - GPE level within the GPE block107*108* RETURN: Status109*110* DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is111* hardware-enabled.112*113******************************************************************************/114115acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)116{117acpi_status status = AE_BAD_PARAMETER;118struct acpi_gpe_event_info *gpe_event_info;119acpi_cpu_flags flags;120121ACPI_FUNCTION_TRACE(acpi_enable_gpe);122123flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);124125/* Ensure that we have a valid GPE number */126127gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);128if (gpe_event_info) {129status = acpi_ev_add_gpe_reference(gpe_event_info);130}131132acpi_os_release_lock(acpi_gbl_gpe_lock, flags);133return_ACPI_STATUS(status);134}135ACPI_EXPORT_SYMBOL(acpi_enable_gpe)136137/*******************************************************************************138*139* FUNCTION: acpi_disable_gpe140*141* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1142* gpe_number - GPE level within the GPE block143*144* RETURN: Status145*146* DESCRIPTION: Remove a reference to a GPE. When the last reference is147* removed, only then is the GPE disabled (for runtime GPEs), or148* the GPE mask bit disabled (for wake GPEs)149*150******************************************************************************/151152acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)153{154acpi_status status = AE_BAD_PARAMETER;155struct acpi_gpe_event_info *gpe_event_info;156acpi_cpu_flags flags;157158ACPI_FUNCTION_TRACE(acpi_disable_gpe);159160flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);161162/* Ensure that we have a valid GPE number */163164gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);165if (gpe_event_info) {166status = acpi_ev_remove_gpe_reference(gpe_event_info) ;167}168169acpi_os_release_lock(acpi_gbl_gpe_lock, flags);170return_ACPI_STATUS(status);171}172ACPI_EXPORT_SYMBOL(acpi_disable_gpe)173174175/*******************************************************************************176*177* FUNCTION: acpi_setup_gpe_for_wake178*179* PARAMETERS: wake_device - Device associated with the GPE (via _PRW)180* gpe_device - Parent GPE Device. NULL for GPE0/GPE1181* gpe_number - GPE level within the GPE block182*183* RETURN: Status184*185* DESCRIPTION: Mark a GPE as having the ability to wake the system. This186* interface is intended to be used as the host executes the187* _PRW methods (Power Resources for Wake) in the system tables.188* Each _PRW appears under a Device Object (The wake_device), and189* contains the info for the wake GPE associated with the190* wake_device.191*192******************************************************************************/193acpi_status194acpi_setup_gpe_for_wake(acpi_handle wake_device,195acpi_handle gpe_device, u32 gpe_number)196{197acpi_status status = AE_BAD_PARAMETER;198struct acpi_gpe_event_info *gpe_event_info;199struct acpi_namespace_node *device_node;200struct acpi_gpe_notify_object *notify_object;201acpi_cpu_flags flags;202u8 gpe_dispatch_mask;203204ACPI_FUNCTION_TRACE(acpi_setup_gpe_for_wake);205206/* Parameter Validation */207208if (!wake_device) {209/*210* By forcing wake_device to be valid, we automatically enable the211* implicit notify feature on all hosts.212*/213return_ACPI_STATUS(AE_BAD_PARAMETER);214}215216flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);217218/* Ensure that we have a valid GPE number */219220gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);221if (!gpe_event_info) {222goto unlock_and_exit;223}224225if (wake_device == ACPI_ROOT_OBJECT) {226goto out;227}228229/*230* If there is no method or handler for this GPE, then the231* wake_device will be notified whenever this GPE fires (aka232* "implicit notify") Note: The GPE is assumed to be233* level-triggered (for windows compatibility).234*/235gpe_dispatch_mask = gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK;236if (gpe_dispatch_mask != ACPI_GPE_DISPATCH_NONE237&& gpe_dispatch_mask != ACPI_GPE_DISPATCH_NOTIFY) {238goto out;239}240241/* Validate wake_device is of type Device */242243device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device);244if (device_node->type != ACPI_TYPE_DEVICE) {245goto unlock_and_exit;246}247248if (gpe_dispatch_mask == ACPI_GPE_DISPATCH_NONE) {249gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY |250ACPI_GPE_LEVEL_TRIGGERED);251gpe_event_info->dispatch.device.node = device_node;252gpe_event_info->dispatch.device.next = NULL;253} else {254/* There are multiple devices to notify implicitly. */255256notify_object = ACPI_ALLOCATE_ZEROED(sizeof(*notify_object));257if (!notify_object) {258status = AE_NO_MEMORY;259goto unlock_and_exit;260}261262notify_object->node = device_node;263notify_object->next = gpe_event_info->dispatch.device.next;264gpe_event_info->dispatch.device.next = notify_object;265}266267out:268gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;269status = AE_OK;270271unlock_and_exit:272acpi_os_release_lock(acpi_gbl_gpe_lock, flags);273return_ACPI_STATUS(status);274}275ACPI_EXPORT_SYMBOL(acpi_setup_gpe_for_wake)276277/*******************************************************************************278*279* FUNCTION: acpi_set_gpe_wake_mask280*281* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1282* gpe_number - GPE level within the GPE block283* Action - Enable or Disable284*285* RETURN: Status286*287* DESCRIPTION: Set or clear the GPE's wakeup enable mask bit. The GPE must288* already be marked as a WAKE GPE.289*290******************************************************************************/291292acpi_status acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action)293{294acpi_status status = AE_OK;295struct acpi_gpe_event_info *gpe_event_info;296struct acpi_gpe_register_info *gpe_register_info;297acpi_cpu_flags flags;298u32 register_bit;299300ACPI_FUNCTION_TRACE(acpi_set_gpe_wake_mask);301302flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);303304/*305* Ensure that we have a valid GPE number and that this GPE is in306* fact a wake GPE307*/308gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);309if (!gpe_event_info) {310status = AE_BAD_PARAMETER;311goto unlock_and_exit;312}313314if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {315status = AE_TYPE;316goto unlock_and_exit;317}318319gpe_register_info = gpe_event_info->register_info;320if (!gpe_register_info) {321status = AE_NOT_EXIST;322goto unlock_and_exit;323}324325register_bit =326acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info);327328/* Perform the action */329330switch (action) {331case ACPI_GPE_ENABLE:332ACPI_SET_BIT(gpe_register_info->enable_for_wake,333(u8)register_bit);334break;335336case ACPI_GPE_DISABLE:337ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake,338(u8)register_bit);339break;340341default:342ACPI_ERROR((AE_INFO, "%u, Invalid action", action));343status = AE_BAD_PARAMETER;344break;345}346347unlock_and_exit:348acpi_os_release_lock(acpi_gbl_gpe_lock, flags);349return_ACPI_STATUS(status);350}351352ACPI_EXPORT_SYMBOL(acpi_set_gpe_wake_mask)353354/*******************************************************************************355*356* FUNCTION: acpi_clear_gpe357*358* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1359* gpe_number - GPE level within the GPE block360*361* RETURN: Status362*363* DESCRIPTION: Clear an ACPI event (general purpose)364*365******************************************************************************/366acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number)367{368acpi_status status = AE_OK;369struct acpi_gpe_event_info *gpe_event_info;370acpi_cpu_flags flags;371372ACPI_FUNCTION_TRACE(acpi_clear_gpe);373374flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);375376/* Ensure that we have a valid GPE number */377378gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);379if (!gpe_event_info) {380status = AE_BAD_PARAMETER;381goto unlock_and_exit;382}383384status = acpi_hw_clear_gpe(gpe_event_info);385386unlock_and_exit:387acpi_os_release_lock(acpi_gbl_gpe_lock, flags);388return_ACPI_STATUS(status);389}390391ACPI_EXPORT_SYMBOL(acpi_clear_gpe)392393/*******************************************************************************394*395* FUNCTION: acpi_get_gpe_status396*397* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1398* gpe_number - GPE level within the GPE block399* event_status - Where the current status of the event will400* be returned401*402* RETURN: Status403*404* DESCRIPTION: Get the current status of a GPE (signalled/not_signalled)405*406******************************************************************************/407acpi_status408acpi_get_gpe_status(acpi_handle gpe_device,409u32 gpe_number, acpi_event_status *event_status)410{411acpi_status status = AE_OK;412struct acpi_gpe_event_info *gpe_event_info;413acpi_cpu_flags flags;414415ACPI_FUNCTION_TRACE(acpi_get_gpe_status);416417flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);418419/* Ensure that we have a valid GPE number */420421gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);422if (!gpe_event_info) {423status = AE_BAD_PARAMETER;424goto unlock_and_exit;425}426427/* Obtain status on the requested GPE number */428429status = acpi_hw_get_gpe_status(gpe_event_info, event_status);430431if (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)432*event_status |= ACPI_EVENT_FLAG_HANDLE;433434unlock_and_exit:435acpi_os_release_lock(acpi_gbl_gpe_lock, flags);436return_ACPI_STATUS(status);437}438439ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)440441/******************************************************************************442*443* FUNCTION: acpi_disable_all_gpes444*445* PARAMETERS: None446*447* RETURN: Status448*449* DESCRIPTION: Disable and clear all GPEs in all GPE blocks450*451******************************************************************************/452453acpi_status acpi_disable_all_gpes(void)454{455acpi_status status;456457ACPI_FUNCTION_TRACE(acpi_disable_all_gpes);458459status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);460if (ACPI_FAILURE(status)) {461return_ACPI_STATUS(status);462}463464status = acpi_hw_disable_all_gpes();465(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);466467return_ACPI_STATUS(status);468}469470ACPI_EXPORT_SYMBOL(acpi_disable_all_gpes)471472/******************************************************************************473*474* FUNCTION: acpi_enable_all_runtime_gpes475*476* PARAMETERS: None477*478* RETURN: Status479*480* DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks481*482******************************************************************************/483484acpi_status acpi_enable_all_runtime_gpes(void)485{486acpi_status status;487488ACPI_FUNCTION_TRACE(acpi_enable_all_runtime_gpes);489490status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);491if (ACPI_FAILURE(status)) {492return_ACPI_STATUS(status);493}494495status = acpi_hw_enable_all_runtime_gpes();496(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);497498return_ACPI_STATUS(status);499}500501ACPI_EXPORT_SYMBOL(acpi_enable_all_runtime_gpes)502503/*******************************************************************************504*505* FUNCTION: acpi_install_gpe_block506*507* PARAMETERS: gpe_device - Handle to the parent GPE Block Device508* gpe_block_address - Address and space_iD509* register_count - Number of GPE register pairs in the block510* interrupt_number - H/W interrupt for the block511*512* RETURN: Status513*514* DESCRIPTION: Create and Install a block of GPE registers. The GPEs are not515* enabled here.516*517******************************************************************************/518acpi_status519acpi_install_gpe_block(acpi_handle gpe_device,520struct acpi_generic_address *gpe_block_address,521u32 register_count, u32 interrupt_number)522{523acpi_status status;524union acpi_operand_object *obj_desc;525struct acpi_namespace_node *node;526struct acpi_gpe_block_info *gpe_block;527528ACPI_FUNCTION_TRACE(acpi_install_gpe_block);529530if ((!gpe_device) || (!gpe_block_address) || (!register_count)) {531return_ACPI_STATUS(AE_BAD_PARAMETER);532}533534status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);535if (ACPI_FAILURE(status)) {536return (status);537}538539node = acpi_ns_validate_handle(gpe_device);540if (!node) {541status = AE_BAD_PARAMETER;542goto unlock_and_exit;543}544545/*546* For user-installed GPE Block Devices, the gpe_block_base_number547* is always zero548*/549status =550acpi_ev_create_gpe_block(node, gpe_block_address, register_count, 0,551interrupt_number, &gpe_block);552if (ACPI_FAILURE(status)) {553goto unlock_and_exit;554}555556/* Install block in the device_object attached to the node */557558obj_desc = acpi_ns_get_attached_object(node);559if (!obj_desc) {560561/*562* No object, create a new one (Device nodes do not always have563* an attached object)564*/565obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_DEVICE);566if (!obj_desc) {567status = AE_NO_MEMORY;568goto unlock_and_exit;569}570571status =572acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_DEVICE);573574/* Remove local reference to the object */575576acpi_ut_remove_reference(obj_desc);577578if (ACPI_FAILURE(status)) {579goto unlock_and_exit;580}581}582583/* Now install the GPE block in the device_object */584585obj_desc->device.gpe_block = gpe_block;586587unlock_and_exit:588(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);589return_ACPI_STATUS(status);590}591592ACPI_EXPORT_SYMBOL(acpi_install_gpe_block)593594/*******************************************************************************595*596* FUNCTION: acpi_remove_gpe_block597*598* PARAMETERS: gpe_device - Handle to the parent GPE Block Device599*600* RETURN: Status601*602* DESCRIPTION: Remove a previously installed block of GPE registers603*604******************************************************************************/605acpi_status acpi_remove_gpe_block(acpi_handle gpe_device)606{607union acpi_operand_object *obj_desc;608acpi_status status;609struct acpi_namespace_node *node;610611ACPI_FUNCTION_TRACE(acpi_remove_gpe_block);612613if (!gpe_device) {614return_ACPI_STATUS(AE_BAD_PARAMETER);615}616617status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);618if (ACPI_FAILURE(status)) {619return (status);620}621622node = acpi_ns_validate_handle(gpe_device);623if (!node) {624status = AE_BAD_PARAMETER;625goto unlock_and_exit;626}627628/* Get the device_object attached to the node */629630obj_desc = acpi_ns_get_attached_object(node);631if (!obj_desc || !obj_desc->device.gpe_block) {632return_ACPI_STATUS(AE_NULL_OBJECT);633}634635/* Delete the GPE block (but not the device_object) */636637status = acpi_ev_delete_gpe_block(obj_desc->device.gpe_block);638if (ACPI_SUCCESS(status)) {639obj_desc->device.gpe_block = NULL;640}641642unlock_and_exit:643(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);644return_ACPI_STATUS(status);645}646647ACPI_EXPORT_SYMBOL(acpi_remove_gpe_block)648649/*******************************************************************************650*651* FUNCTION: acpi_get_gpe_device652*653* PARAMETERS: Index - System GPE index (0-current_gpe_count)654* gpe_device - Where the parent GPE Device is returned655*656* RETURN: Status657*658* DESCRIPTION: Obtain the GPE device associated with the input index. A NULL659* gpe device indicates that the gpe number is contained in one of660* the FADT-defined gpe blocks. Otherwise, the GPE block device.661*662******************************************************************************/663acpi_status664acpi_get_gpe_device(u32 index, acpi_handle *gpe_device)665{666struct acpi_gpe_device_info info;667acpi_status status;668669ACPI_FUNCTION_TRACE(acpi_get_gpe_device);670671if (!gpe_device) {672return_ACPI_STATUS(AE_BAD_PARAMETER);673}674675if (index >= acpi_current_gpe_count) {676return_ACPI_STATUS(AE_NOT_EXIST);677}678679/* Setup and walk the GPE list */680681info.index = index;682info.status = AE_NOT_EXIST;683info.gpe_device = NULL;684info.next_block_base_index = 0;685686status = acpi_ev_walk_gpe_list(acpi_ev_get_gpe_device, &info);687if (ACPI_FAILURE(status)) {688return_ACPI_STATUS(status);689}690691*gpe_device = ACPI_CAST_PTR(acpi_handle, info.gpe_device);692return_ACPI_STATUS(info.status);693}694695ACPI_EXPORT_SYMBOL(acpi_get_gpe_device)696697698