linux/drivers/acpi/acpica/evxfregn.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: evxfregn - External Interfaces, ACPI Operation Regions and
   5 *                         Address Spaces.
   6 *
   7 * Copyright (C) 2000 - 2021, Intel Corp.
   8 *
   9 *****************************************************************************/
  10
  11#define EXPORT_ACPI_INTERFACES
  12
  13#include <acpi/acpi.h>
  14#include "accommon.h"
  15#include "acnamesp.h"
  16#include "acevents.h"
  17
  18#define _COMPONENT          ACPI_EVENTS
  19ACPI_MODULE_NAME("evxfregn")
  20
  21/*******************************************************************************
  22 *
  23 * FUNCTION:    acpi_install_address_space_handler
  24 *
  25 * PARAMETERS:  device          - Handle for the device
  26 *              space_id        - The address space ID
  27 *              handler         - Address of the handler
  28 *              setup           - Address of the setup function
  29 *              context         - Value passed to the handler on each access
  30 *
  31 * RETURN:      Status
  32 *
  33 * DESCRIPTION: Install a handler for all op_regions of a given space_id.
  34 *
  35 * NOTE: This function should only be called after acpi_enable_subsystem has
  36 * been called. This is because any _REG methods associated with the Space ID
  37 * are executed here, and these methods can only be safely executed after
  38 * the default handlers have been installed and the hardware has been
  39 * initialized (via acpi_enable_subsystem.)
  40 *
  41 ******************************************************************************/
  42acpi_status
  43acpi_install_address_space_handler(acpi_handle device,
  44                                   acpi_adr_space_type space_id,
  45                                   acpi_adr_space_handler handler,
  46                                   acpi_adr_space_setup setup, void *context)
  47{
  48        struct acpi_namespace_node *node;
  49        acpi_status status;
  50
  51        ACPI_FUNCTION_TRACE(acpi_install_address_space_handler);
  52
  53        /* Parameter validation */
  54
  55        if (!device) {
  56                return_ACPI_STATUS(AE_BAD_PARAMETER);
  57        }
  58
  59        status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
  60        if (ACPI_FAILURE(status)) {
  61                return_ACPI_STATUS(status);
  62        }
  63
  64        /* Convert and validate the device handle */
  65
  66        node = acpi_ns_validate_handle(device);
  67        if (!node) {
  68                status = AE_BAD_PARAMETER;
  69                goto unlock_and_exit;
  70        }
  71
  72        /* Install the handler for all Regions for this Space ID */
  73
  74        status =
  75            acpi_ev_install_space_handler(node, space_id, handler, setup,
  76                                          context);
  77        if (ACPI_FAILURE(status)) {
  78                goto unlock_and_exit;
  79        }
  80
  81        /* Run all _REG methods for this address space */
  82
  83        acpi_ev_execute_reg_methods(node, space_id, ACPI_REG_CONNECT);
  84
  85unlock_and_exit:
  86        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
  87        return_ACPI_STATUS(status);
  88}
  89
  90ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler)
  91
  92/*******************************************************************************
  93 *
  94 * FUNCTION:    acpi_remove_address_space_handler
  95 *
  96 * PARAMETERS:  device          - Handle for the device
  97 *              space_id        - The address space ID
  98 *              handler         - Address of the handler
  99 *
 100 * RETURN:      Status
 101 *
 102 * DESCRIPTION: Remove a previously installed handler.
 103 *
 104 ******************************************************************************/
 105acpi_status
 106acpi_remove_address_space_handler(acpi_handle device,
 107                                  acpi_adr_space_type space_id,
 108                                  acpi_adr_space_handler handler)
 109{
 110        union acpi_operand_object *obj_desc;
 111        union acpi_operand_object *handler_obj;
 112        union acpi_operand_object *region_obj;
 113        union acpi_operand_object **last_obj_ptr;
 114        struct acpi_namespace_node *node;
 115        acpi_status status;
 116
 117        ACPI_FUNCTION_TRACE(acpi_remove_address_space_handler);
 118
 119        /* Parameter validation */
 120
 121        if (!device) {
 122                return_ACPI_STATUS(AE_BAD_PARAMETER);
 123        }
 124
 125        status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
 126        if (ACPI_FAILURE(status)) {
 127                return_ACPI_STATUS(status);
 128        }
 129
 130        /* Convert and validate the device handle */
 131
 132        node = acpi_ns_validate_handle(device);
 133        if (!node ||
 134            ((node->type != ACPI_TYPE_DEVICE) &&
 135             (node->type != ACPI_TYPE_PROCESSOR) &&
 136             (node->type != ACPI_TYPE_THERMAL) &&
 137             (node != acpi_gbl_root_node))) {
 138                status = AE_BAD_PARAMETER;
 139                goto unlock_and_exit;
 140        }
 141
 142        /* Make sure the internal object exists */
 143
 144        obj_desc = acpi_ns_get_attached_object(node);
 145        if (!obj_desc) {
 146                status = AE_NOT_EXIST;
 147                goto unlock_and_exit;
 148        }
 149
 150        /* Find the address handler the user requested */
 151
 152        handler_obj = obj_desc->common_notify.handler;
 153        last_obj_ptr = &obj_desc->common_notify.handler;
 154        while (handler_obj) {
 155
 156                /* We have a handler, see if user requested this one */
 157
 158                if (handler_obj->address_space.space_id == space_id) {
 159
 160                        /* Handler must be the same as the installed handler */
 161
 162                        if (handler_obj->address_space.handler != handler) {
 163                                status = AE_BAD_PARAMETER;
 164                                goto unlock_and_exit;
 165                        }
 166
 167                        /* Matched space_id, first dereference this in the Regions */
 168
 169                        ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
 170                                          "Removing address handler %p(%p) for region %s "
 171                                          "on Device %p(%p)\n",
 172                                          handler_obj, handler,
 173                                          acpi_ut_get_region_name(space_id),
 174                                          node, obj_desc));
 175
 176                        region_obj = handler_obj->address_space.region_list;
 177
 178                        /* Walk the handler's region list */
 179
 180                        while (region_obj) {
 181                                /*
 182                                 * First disassociate the handler from the region.
 183                                 *
 184                                 * NOTE: this doesn't mean that the region goes away
 185                                 * The region is just inaccessible as indicated to
 186                                 * the _REG method
 187                                 */
 188                                acpi_ev_detach_region(region_obj, TRUE);
 189
 190                                /*
 191                                 * Walk the list: Just grab the head because the
 192                                 * detach_region removed the previous head.
 193                                 */
 194                                region_obj =
 195                                    handler_obj->address_space.region_list;
 196                        }
 197
 198                        /* Remove this Handler object from the list */
 199
 200                        *last_obj_ptr = handler_obj->address_space.next;
 201
 202                        /* Now we can delete the handler object */
 203
 204                        acpi_os_release_mutex(handler_obj->address_space.
 205                                              context_mutex);
 206                        acpi_ut_remove_reference(handler_obj);
 207                        goto unlock_and_exit;
 208                }
 209
 210                /* Walk the linked list of handlers */
 211
 212                last_obj_ptr = &handler_obj->address_space.next;
 213                handler_obj = handler_obj->address_space.next;
 214        }
 215
 216        /* The handler does not exist */
 217
 218        ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
 219                          "Unable to remove address handler %p for %s(%X), DevNode %p, obj %p\n",
 220                          handler, acpi_ut_get_region_name(space_id), space_id,
 221                          node, obj_desc));
 222
 223        status = AE_NOT_EXIST;
 224
 225unlock_and_exit:
 226        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 227        return_ACPI_STATUS(status);
 228}
 229
 230ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler)
 231