Branch data Line data Source code
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 - 2020, 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 19 : : ACPI_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 : : ******************************************************************************/ 42 : : acpi_status 43 : 26 : acpi_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 : 26 : struct acpi_namespace_node *node; 49 : 26 : acpi_status status; 50 : : 51 : 26 : ACPI_FUNCTION_TRACE(acpi_install_address_space_handler); 52 : : 53 : : /* Parameter validation */ 54 : : 55 [ + - ]: 26 : if (!device) { 56 : : return_ACPI_STATUS(AE_BAD_PARAMETER); 57 : : } 58 : : 59 : 26 : status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 60 [ + - ]: 26 : if (ACPI_FAILURE(status)) { 61 : : return_ACPI_STATUS(status); 62 : : } 63 : : 64 : : /* Convert and validate the device handle */ 65 : : 66 : 26 : node = acpi_ns_validate_handle(device); 67 [ - + ]: 26 : if (!node) { 68 : 0 : status = AE_BAD_PARAMETER; 69 : 0 : goto unlock_and_exit; 70 : : } 71 : : 72 : : /* Install the handler for all Regions for this Space ID */ 73 : : 74 : 26 : status = 75 : 26 : acpi_ev_install_space_handler(node, space_id, handler, setup, 76 : : context); 77 [ - + ]: 26 : if (ACPI_FAILURE(status)) { 78 : 0 : goto unlock_and_exit; 79 : : } 80 : : 81 : : /* Run all _REG methods for this address space */ 82 : : 83 : 26 : acpi_ev_execute_reg_methods(node, space_id, ACPI_REG_CONNECT); 84 : : 85 : 26 : unlock_and_exit: 86 : 26 : (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 87 : 26 : return_ACPI_STATUS(status); 88 : : } 89 : : 90 : : ACPI_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 : : ******************************************************************************/ 105 : : acpi_status 106 : 0 : acpi_remove_address_space_handler(acpi_handle device, 107 : : acpi_adr_space_type space_id, 108 : : acpi_adr_space_handler handler) 109 : : { 110 : 0 : union acpi_operand_object *obj_desc; 111 : 0 : union acpi_operand_object *handler_obj; 112 : 0 : union acpi_operand_object *region_obj; 113 : 0 : union acpi_operand_object **last_obj_ptr; 114 : 0 : struct acpi_namespace_node *node; 115 : 0 : acpi_status status; 116 : : 117 : 0 : ACPI_FUNCTION_TRACE(acpi_remove_address_space_handler); 118 : : 119 : : /* Parameter validation */ 120 : : 121 [ # # ]: 0 : if (!device) { 122 : : return_ACPI_STATUS(AE_BAD_PARAMETER); 123 : : } 124 : : 125 : 0 : status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 126 [ # # ]: 0 : if (ACPI_FAILURE(status)) { 127 : : return_ACPI_STATUS(status); 128 : : } 129 : : 130 : : /* Convert and validate the device handle */ 131 : : 132 : 0 : node = acpi_ns_validate_handle(device); 133 [ # # ]: 0 : if (!node || 134 [ # # ]: 0 : ((node->type != ACPI_TYPE_DEVICE) && 135 [ # # ]: 0 : (node->type != ACPI_TYPE_PROCESSOR) && 136 : 0 : (node->type != ACPI_TYPE_THERMAL) && 137 [ # # ]: 0 : (node != acpi_gbl_root_node))) { 138 : 0 : status = AE_BAD_PARAMETER; 139 : 0 : goto unlock_and_exit; 140 : : } 141 : : 142 : : /* Make sure the internal object exists */ 143 : : 144 : 0 : obj_desc = acpi_ns_get_attached_object(node); 145 [ # # ]: 0 : if (!obj_desc) { 146 : 0 : status = AE_NOT_EXIST; 147 : 0 : goto unlock_and_exit; 148 : : } 149 : : 150 : : /* Find the address handler the user requested */ 151 : : 152 : 0 : handler_obj = obj_desc->common_notify.handler; 153 : 0 : last_obj_ptr = &obj_desc->common_notify.handler; 154 [ # # ]: 0 : while (handler_obj) { 155 : : 156 : : /* We have a handler, see if user requested this one */ 157 : : 158 [ # # ]: 0 : if (handler_obj->address_space.space_id == space_id) { 159 : : 160 : : /* Handler must be the same as the installed handler */ 161 : : 162 [ # # ]: 0 : if (handler_obj->address_space.handler != handler) { 163 : 0 : status = AE_BAD_PARAMETER; 164 : 0 : 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 : 0 : node, obj_desc)); 175 : : 176 : 0 : region_obj = handler_obj->address_space.region_list; 177 : : 178 : : /* Walk the handler's region list */ 179 : : 180 [ # # ]: 0 : 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 : 0 : 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 : 0 : region_obj = 195 : : handler_obj->address_space.region_list; 196 : : } 197 : : 198 : : /* Remove this Handler object from the list */ 199 : : 200 : 0 : *last_obj_ptr = handler_obj->address_space.next; 201 : : 202 : : /* Now we can delete the handler object */ 203 : : 204 : 0 : acpi_ut_remove_reference(handler_obj); 205 : 0 : goto unlock_and_exit; 206 : : } 207 : : 208 : : /* Walk the linked list of handlers */ 209 : : 210 : 0 : last_obj_ptr = &handler_obj->address_space.next; 211 : 0 : handler_obj = handler_obj->address_space.next; 212 : : } 213 : : 214 : : /* The handler does not exist */ 215 : : 216 : : ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, 217 : : "Unable to remove address handler %p for %s(%X), DevNode %p, obj %p\n", 218 : : handler, acpi_ut_get_region_name(space_id), space_id, 219 : : node, obj_desc)); 220 : : 221 : : status = AE_NOT_EXIST; 222 : : 223 : 0 : unlock_and_exit: 224 : 0 : (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 225 : 0 : return_ACPI_STATUS(status); 226 : : } 227 : : 228 : : ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler)