/******************************************************************************1*2* Module Name: evxfregn - External Interfaces, ACPI Operation Regions and3* Address Spaces.4*5*****************************************************************************/67/*8* Copyright (C) 2000 - 2011, Intel Corp.9* All rights reserved.10*11* Redistribution and use in source and binary forms, with or without12* modification, are permitted provided that the following conditions13* are met:14* 1. Redistributions of source code must retain the above copyright15* notice, this list of conditions, and the following disclaimer,16* without modification.17* 2. Redistributions in binary form must reproduce at minimum a disclaimer18* substantially similar to the "NO WARRANTY" disclaimer below19* ("Disclaimer") and any redistribution must be conditioned upon20* including a substantially similar Disclaimer requirement for further21* binary redistribution.22* 3. Neither the names of the above-listed copyright holders nor the names23* of any contributors may be used to endorse or promote products derived24* from this software without specific prior written permission.25*26* Alternatively, this software may be distributed under the terms of the27* GNU General Public License ("GPL") version 2 as published by the Free28* Software Foundation.29*30* NO WARRANTY31* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS32* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT33* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR34* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT35* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL36* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS37* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)38* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,39* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING40* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE41* POSSIBILITY OF SUCH DAMAGES.42*/4344#include <acpi/acpi.h>45#include "accommon.h"46#include "acnamesp.h"47#include "acevents.h"4849#define _COMPONENT ACPI_EVENTS50ACPI_MODULE_NAME("evxfregn")5152/*******************************************************************************53*54* FUNCTION: acpi_install_address_space_handler55*56* PARAMETERS: Device - Handle for the device57* space_id - The address space ID58* Handler - Address of the handler59* Setup - Address of the setup function60* Context - Value passed to the handler on each access61*62* RETURN: Status63*64* DESCRIPTION: Install a handler for all op_regions of a given space_id.65*66* NOTE: This function should only be called after acpi_enable_subsystem has67* been called. This is because any _REG methods associated with the Space ID68* are executed here, and these methods can only be safely executed after69* the default handlers have been installed and the hardware has been70* initialized (via acpi_enable_subsystem.)71*72******************************************************************************/73acpi_status74acpi_install_address_space_handler(acpi_handle device,75acpi_adr_space_type space_id,76acpi_adr_space_handler handler,77acpi_adr_space_setup setup, void *context)78{79struct acpi_namespace_node *node;80acpi_status status;8182ACPI_FUNCTION_TRACE(acpi_install_address_space_handler);8384/* Parameter validation */8586if (!device) {87return_ACPI_STATUS(AE_BAD_PARAMETER);88}8990status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);91if (ACPI_FAILURE(status)) {92return_ACPI_STATUS(status);93}9495/* Convert and validate the device handle */9697node = acpi_ns_validate_handle(device);98if (!node) {99status = AE_BAD_PARAMETER;100goto unlock_and_exit;101}102103/* Install the handler for all Regions for this Space ID */104105status =106acpi_ev_install_space_handler(node, space_id, handler, setup,107context);108if (ACPI_FAILURE(status)) {109goto unlock_and_exit;110}111112/*113* For the default space_iDs, (the IDs for which there are default region handlers114* installed) Only execute the _REG methods if the global initialization _REG115* methods have already been run (via acpi_initialize_objects). In other words,116* we will defer the execution of the _REG methods for these space_iDs until117* execution of acpi_initialize_objects. This is done because we need the handlers118* for the default spaces (mem/io/pci/table) to be installed before we can run119* any control methods (or _REG methods). There is known BIOS code that depends120* on this.121*122* For all other space_iDs, we can safely execute the _REG methods immediately.123* This means that for IDs like embedded_controller, this function should be called124* only after acpi_enable_subsystem has been called.125*/126switch (space_id) {127case ACPI_ADR_SPACE_SYSTEM_MEMORY:128case ACPI_ADR_SPACE_SYSTEM_IO:129case ACPI_ADR_SPACE_PCI_CONFIG:130case ACPI_ADR_SPACE_DATA_TABLE:131132if (!acpi_gbl_reg_methods_executed) {133134/* We will defer execution of the _REG methods for this space */135goto unlock_and_exit;136}137break;138139default:140break;141}142143/* Run all _REG methods for this address space */144145status = acpi_ev_execute_reg_methods(node, space_id);146147unlock_and_exit:148(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);149return_ACPI_STATUS(status);150}151152ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler)153154/*******************************************************************************155*156* FUNCTION: acpi_remove_address_space_handler157*158* PARAMETERS: Device - Handle for the device159* space_id - The address space ID160* Handler - Address of the handler161*162* RETURN: Status163*164* DESCRIPTION: Remove a previously installed handler.165*166******************************************************************************/167acpi_status168acpi_remove_address_space_handler(acpi_handle device,169acpi_adr_space_type space_id,170acpi_adr_space_handler handler)171{172union acpi_operand_object *obj_desc;173union acpi_operand_object *handler_obj;174union acpi_operand_object *region_obj;175union acpi_operand_object **last_obj_ptr;176struct acpi_namespace_node *node;177acpi_status status;178179ACPI_FUNCTION_TRACE(acpi_remove_address_space_handler);180181/* Parameter validation */182183if (!device) {184return_ACPI_STATUS(AE_BAD_PARAMETER);185}186187status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);188if (ACPI_FAILURE(status)) {189return_ACPI_STATUS(status);190}191192/* Convert and validate the device handle */193194node = acpi_ns_validate_handle(device);195if (!node ||196((node->type != ACPI_TYPE_DEVICE) &&197(node->type != ACPI_TYPE_PROCESSOR) &&198(node->type != ACPI_TYPE_THERMAL) &&199(node != acpi_gbl_root_node))) {200status = AE_BAD_PARAMETER;201goto unlock_and_exit;202}203204/* Make sure the internal object exists */205206obj_desc = acpi_ns_get_attached_object(node);207if (!obj_desc) {208status = AE_NOT_EXIST;209goto unlock_and_exit;210}211212/* Find the address handler the user requested */213214handler_obj = obj_desc->device.handler;215last_obj_ptr = &obj_desc->device.handler;216while (handler_obj) {217218/* We have a handler, see if user requested this one */219220if (handler_obj->address_space.space_id == space_id) {221222/* Handler must be the same as the installed handler */223224if (handler_obj->address_space.handler != handler) {225status = AE_BAD_PARAMETER;226goto unlock_and_exit;227}228229/* Matched space_id, first dereference this in the Regions */230231ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,232"Removing address handler %p(%p) for region %s "233"on Device %p(%p)\n",234handler_obj, handler,235acpi_ut_get_region_name(space_id),236node, obj_desc));237238region_obj = handler_obj->address_space.region_list;239240/* Walk the handler's region list */241242while (region_obj) {243/*244* First disassociate the handler from the region.245*246* NOTE: this doesn't mean that the region goes away247* The region is just inaccessible as indicated to248* the _REG method249*/250acpi_ev_detach_region(region_obj, TRUE);251252/*253* Walk the list: Just grab the head because the254* detach_region removed the previous head.255*/256region_obj =257handler_obj->address_space.region_list;258259}260261/* Remove this Handler object from the list */262263*last_obj_ptr = handler_obj->address_space.next;264265/* Now we can delete the handler object */266267acpi_ut_remove_reference(handler_obj);268goto unlock_and_exit;269}270271/* Walk the linked list of handlers */272273last_obj_ptr = &handler_obj->address_space.next;274handler_obj = handler_obj->address_space.next;275}276277/* The handler does not exist */278279ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,280"Unable to remove address handler %p for %s(%X), DevNode %p, obj %p\n",281handler, acpi_ut_get_region_name(space_id), space_id,282node, obj_desc));283284status = AE_NOT_EXIST;285286unlock_and_exit:287(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);288return_ACPI_STATUS(status);289}290291ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler)292293294