File Index
Files and directories
Sign in
FILE

evxfregn.c

File preview with syntax highlighting.

linux-6.19.14/drivers/acpi/acpica/evxfregn.c C
  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 - 2025, 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_internal
 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 *              Run_reg         - Run _REG methods for this address space?
 31 *
 32 * RETURN:      Status
 33 *
 34 * DESCRIPTION: Install a handler for all op_regions of a given space_id.
 35 *
 36 * NOTE: This function should only be called after acpi_enable_subsystem has
 37 * been called. This is because any _REG methods associated with the Space ID
 38 * are executed here, and these methods can only be safely executed after
 39 * the default handlers have been installed and the hardware has been
 40 * initialized (via acpi_enable_subsystem.)
 41 * To avoid this problem pass FALSE for Run_Reg and later on call
 42 * acpi_execute_reg_methods() to execute _REG.
 43 *
 44 ******************************************************************************/
 45static acpi_status
 46acpi_install_address_space_handler_internal(acpi_handle device,
 47					    acpi_adr_space_type space_id,
 48					    acpi_adr_space_handler handler,
 49					    acpi_adr_space_setup setup,
 50					    void *context, u8 run_reg)
 51{
 52	struct acpi_namespace_node *node;
 53	acpi_status status;
 54
 55	ACPI_FUNCTION_TRACE(acpi_install_address_space_handler);
 56
 57	/* Parameter validation */
 58
 59	if (!device) {
 60		return_ACPI_STATUS(AE_BAD_PARAMETER);
 61	}
 62
 63	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
 64	if (ACPI_FAILURE(status)) {
 65		return_ACPI_STATUS(status);
 66	}
 67
 68	/* Convert and validate the device handle */
 69
 70	node = acpi_ns_validate_handle(device);
 71	if (!node) {
 72		status = AE_BAD_PARAMETER;
 73		goto unlock_and_exit;
 74	}
 75
 76	/* Install the handler for all Regions for this Space ID */
 77
 78	status =
 79	    acpi_ev_install_space_handler(node, space_id, handler, setup,
 80					  context);
 81	if (ACPI_FAILURE(status)) {
 82		goto unlock_and_exit;
 83	}
 84
 85	/* Run all _REG methods for this address space */
 86
 87	if (run_reg) {
 88		acpi_ev_execute_reg_methods(node, ACPI_UINT32_MAX, space_id,
 89					    ACPI_REG_CONNECT);
 90	}
 91
 92unlock_and_exit:
 93	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 94	return_ACPI_STATUS(status);
 95}
 96
 97acpi_status
 98acpi_install_address_space_handler(acpi_handle device,
 99				   acpi_adr_space_type space_id,
100				   acpi_adr_space_handler handler,
101				   acpi_adr_space_setup setup, void *context)
102{
103	return acpi_install_address_space_handler_internal(device, space_id,
104							   handler, setup,
105							   context, TRUE);
106}
107
108ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler)
109acpi_status
110acpi_install_address_space_handler_no_reg(acpi_handle device,
111					  acpi_adr_space_type space_id,
112					  acpi_adr_space_handler handler,
113					  acpi_adr_space_setup setup,
114					  void *context)
115{
116	return acpi_install_address_space_handler_internal(device, space_id,
117							   handler, setup,
118							   context, FALSE);
119}
120
121ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler_no_reg)
122
123/*******************************************************************************
124 *
125 * FUNCTION:    acpi_remove_address_space_handler
126 *
127 * PARAMETERS:  device          - Handle for the device
128 *              space_id        - The address space ID
129 *              handler         - Address of the handler
130 *
131 * RETURN:      Status
132 *
133 * DESCRIPTION: Remove a previously installed handler.
134 *
135 ******************************************************************************/
136acpi_status
137acpi_remove_address_space_handler(acpi_handle device,
138				  acpi_adr_space_type space_id,
139				  acpi_adr_space_handler handler)
140{
141	union acpi_operand_object *obj_desc;
142	union acpi_operand_object *handler_obj;
143	union acpi_operand_object *region_obj;
144	union acpi_operand_object **last_obj_ptr;
145	struct acpi_namespace_node *node;
146	acpi_status status;
147
148	ACPI_FUNCTION_TRACE(acpi_remove_address_space_handler);
149
150	/* Parameter validation */
151
152	if (!device) {
153		return_ACPI_STATUS(AE_BAD_PARAMETER);
154	}
155
156	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
157	if (ACPI_FAILURE(status)) {
158		return_ACPI_STATUS(status);
159	}
160
161	/* Convert and validate the device handle */
162
163	node = acpi_ns_validate_handle(device);
164	if (!node ||
165	    ((node->type != ACPI_TYPE_DEVICE) &&
166	     (node->type != ACPI_TYPE_PROCESSOR) &&
167	     (node->type != ACPI_TYPE_THERMAL) &&
168	     (node != acpi_gbl_root_node))) {
169		status = AE_BAD_PARAMETER;
170		goto unlock_and_exit;
171	}
172
173	/* Make sure the internal object exists */
174
175	obj_desc = acpi_ns_get_attached_object(node);
176	if (!obj_desc) {
177		status = AE_NOT_EXIST;
178		goto unlock_and_exit;
179	}
180
181	/* Find the address handler the user requested */
182
183	handler_obj = obj_desc->common_notify.handler;
184	last_obj_ptr = &obj_desc->common_notify.handler;
185	while (handler_obj) {
186
187		/* We have a handler, see if user requested this one */
188
189		if (handler_obj->address_space.space_id == space_id) {
190
191			/* Handler must be the same as the installed handler */
192
193			if (handler_obj->address_space.handler != handler) {
194				status = AE_BAD_PARAMETER;
195				goto unlock_and_exit;
196			}
197
198			/* Matched space_id, first dereference this in the Regions */
199
200			ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
201					  "Removing address handler %p(%p) for region %s "
202					  "on Device %p(%p)\n",
203					  handler_obj, handler,
204					  acpi_ut_get_region_name(space_id),
205					  node, obj_desc));
206
207			region_obj = handler_obj->address_space.region_list;
208
209			/* Walk the handler's region list */
210
211			while (region_obj) {
212				/*
213				 * First disassociate the handler from the region.
214				 *
215				 * NOTE: this doesn't mean that the region goes away
216				 * The region is just inaccessible as indicated to
217				 * the _REG method
218				 */
219				acpi_ev_detach_region(region_obj, TRUE);
220
221				/*
222				 * Walk the list: Just grab the head because the
223				 * detach_region removed the previous head.
224				 */
225				region_obj =
226				    handler_obj->address_space.region_list;
227			}
228
229			/* Remove this Handler object from the list */
230
231			*last_obj_ptr = handler_obj->address_space.next;
232
233			/* Now we can delete the handler object */
234
235			acpi_ut_remove_reference(handler_obj);
236			goto unlock_and_exit;
237		}
238
239		/* Walk the linked list of handlers */
240
241		last_obj_ptr = &handler_obj->address_space.next;
242		handler_obj = handler_obj->address_space.next;
243	}
244
245	/* The handler does not exist */
246
247	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
248			  "Unable to remove address handler %p for %s(%X), DevNode %p, obj %p\n",
249			  handler, acpi_ut_get_region_name(space_id), space_id,
250			  node, obj_desc));
251
252	status = AE_NOT_EXIST;
253
254unlock_and_exit:
255	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
256	return_ACPI_STATUS(status);
257}
258
259ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler)
260/*******************************************************************************
261 *
262 * FUNCTION:    acpi_execute_reg_methods
263 *
264 * PARAMETERS:  device          - Handle for the device
265 *              max_depth       - Depth to which search for _REG
266 *              space_id        - The address space ID
267 *
268 * RETURN:      Status
269 *
270 * DESCRIPTION: Execute _REG for all op_regions of a given space_id.
271 *
272 ******************************************************************************/
273acpi_status
274acpi_execute_reg_methods(acpi_handle device, u32 max_depth,
275			 acpi_adr_space_type space_id)
276{
277	struct acpi_namespace_node *node;
278	acpi_status status;
279
280	ACPI_FUNCTION_TRACE(acpi_execute_reg_methods);
281
282	/* Parameter validation */
283
284	if (!device) {
285		return_ACPI_STATUS(AE_BAD_PARAMETER);
286	}
287
288	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
289	if (ACPI_FAILURE(status)) {
290		return_ACPI_STATUS(status);
291	}
292
293	/* Convert and validate the device handle */
294
295	node = acpi_ns_validate_handle(device);
296	if (node) {
297
298		/* Run all _REG methods for this address space */
299
300		acpi_ev_execute_reg_methods(node, max_depth, space_id,
301					    ACPI_REG_CONNECT);
302	} else {
303		status = AE_BAD_PARAMETER;
304	}
305
306	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
307	return_ACPI_STATUS(status);
308}
309
310ACPI_EXPORT_SYMBOL(acpi_execute_reg_methods)
~/ Read-only file preview.