]>
Commit | Line | Data |
---|---|---|
95857638 | 1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
1da177e4 LT |
2 | /****************************************************************************** |
3 | * | |
4 | * Module Name: evxfregn - External Interfaces, ACPI Operation Regions and | |
5 | * Address Spaces. | |
6 | * | |
800ba7c5 | 7 | * Copyright (C) 2000 - 2020, Intel Corp. |
1da177e4 | 8 | * |
95857638 | 9 | *****************************************************************************/ |
1da177e4 | 10 | |
839e928f LZ |
11 | #define EXPORT_ACPI_INTERFACES |
12 | ||
1da177e4 | 13 | #include <acpi/acpi.h> |
e2f7a777 LB |
14 | #include "accommon.h" |
15 | #include "acnamesp.h" | |
16 | #include "acevents.h" | |
1da177e4 LT |
17 | |
18 | #define _COMPONENT ACPI_EVENTS | |
4be44fcd | 19 | ACPI_MODULE_NAME("evxfregn") |
1da177e4 LT |
20 | |
21 | /******************************************************************************* | |
22 | * | |
23 | * FUNCTION: acpi_install_address_space_handler | |
24 | * | |
ba494bee | 25 | * PARAMETERS: device - Handle for the device |
1da177e4 | 26 | * space_id - The address space ID |
ba494bee BM |
27 | * handler - Address of the handler |
28 | * setup - Address of the setup function | |
29 | * context - Value passed to the handler on each access | |
1da177e4 LT |
30 | * |
31 | * RETURN: Status | |
32 | * | |
33 | * DESCRIPTION: Install a handler for all op_regions of a given space_id. | |
34 | * | |
3989170f BM |
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 | * | |
1da177e4 | 41 | ******************************************************************************/ |
1da177e4 | 42 | acpi_status |
4be44fcd LB |
43 | 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) | |
1da177e4 | 47 | { |
4be44fcd LB |
48 | struct acpi_namespace_node *node; |
49 | acpi_status status; | |
1da177e4 | 50 | |
b229cf92 | 51 | ACPI_FUNCTION_TRACE(acpi_install_address_space_handler); |
1da177e4 LT |
52 | |
53 | /* Parameter validation */ | |
54 | ||
55 | if (!device) { | |
4be44fcd | 56 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
1da177e4 LT |
57 | } |
58 | ||
4be44fcd LB |
59 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
60 | if (ACPI_FAILURE(status)) { | |
61 | return_ACPI_STATUS(status); | |
1da177e4 LT |
62 | } |
63 | ||
64 | /* Convert and validate the device handle */ | |
65 | ||
f24b664d | 66 | node = acpi_ns_validate_handle(device); |
1da177e4 LT |
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 | ||
4be44fcd LB |
74 | status = |
75 | acpi_ev_install_space_handler(node, space_id, handler, setup, | |
76 | context); | |
77 | if (ACPI_FAILURE(status)) { | |
1da177e4 LT |
78 | goto unlock_and_exit; |
79 | } | |
80 | ||
e2066ca1 BM |
81 | /* Run all _REG methods for this address space */ |
82 | ||
d815346f | 83 | acpi_ev_execute_reg_methods(node, space_id, ACPI_REG_CONNECT); |
e2066ca1 | 84 | |
10622bf8 | 85 | unlock_and_exit: |
4be44fcd LB |
86 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
87 | return_ACPI_STATUS(status); | |
1da177e4 | 88 | } |
1da177e4 | 89 | |
8313524a | 90 | ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler) |
1da177e4 LT |
91 | |
92 | /******************************************************************************* | |
93 | * | |
94 | * FUNCTION: acpi_remove_address_space_handler | |
95 | * | |
ba494bee | 96 | * PARAMETERS: device - Handle for the device |
1da177e4 | 97 | * space_id - The address space ID |
ba494bee | 98 | * handler - Address of the handler |
1da177e4 LT |
99 | * |
100 | * RETURN: Status | |
101 | * | |
102 | * DESCRIPTION: Remove a previously installed handler. | |
103 | * | |
104 | ******************************************************************************/ | |
1da177e4 | 105 | acpi_status |
4be44fcd LB |
106 | acpi_remove_address_space_handler(acpi_handle device, |
107 | acpi_adr_space_type space_id, | |
108 | acpi_adr_space_handler handler) | |
1da177e4 | 109 | { |
4be44fcd LB |
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; | |
1da177e4 | 116 | |
b229cf92 | 117 | ACPI_FUNCTION_TRACE(acpi_remove_address_space_handler); |
1da177e4 LT |
118 | |
119 | /* Parameter validation */ | |
120 | ||
121 | if (!device) { | |
4be44fcd | 122 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
1da177e4 LT |
123 | } |
124 | ||
4be44fcd LB |
125 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
126 | if (ACPI_FAILURE(status)) { | |
127 | return_ACPI_STATUS(status); | |
1da177e4 LT |
128 | } |
129 | ||
130 | /* Convert and validate the device handle */ | |
131 | ||
f24b664d | 132 | node = acpi_ns_validate_handle(device); |
f6dd9221 BM |
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))) { | |
1da177e4 LT |
138 | status = AE_BAD_PARAMETER; |
139 | goto unlock_and_exit; | |
140 | } | |
141 | ||
142 | /* Make sure the internal object exists */ | |
143 | ||
4be44fcd | 144 | obj_desc = acpi_ns_get_attached_object(node); |
1da177e4 LT |
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 | ||
aa6abd2b LZ |
152 | handler_obj = obj_desc->common_notify.handler; |
153 | last_obj_ptr = &obj_desc->common_notify.handler; | |
1da177e4 | 154 | while (handler_obj) { |
52fc0b02 | 155 | |
1da177e4 LT |
156 | /* We have a handler, see if user requested this one */ |
157 | ||
158 | if (handler_obj->address_space.space_id == space_id) { | |
52fc0b02 | 159 | |
f6dd9221 BM |
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 | ||
1da177e4 LT |
167 | /* Matched space_id, first dereference this in the Regions */ |
168 | ||
4be44fcd | 169 | ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
d4913dc6 BM |
170 | "Removing address handler %p(%p) for region %s " |
171 | "on Device %p(%p)\n", | |
4be44fcd LB |
172 | handler_obj, handler, |
173 | acpi_ut_get_region_name(space_id), | |
174 | node, obj_desc)); | |
1da177e4 LT |
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 | */ | |
4be44fcd | 188 | acpi_ev_detach_region(region_obj, TRUE); |
1da177e4 LT |
189 | |
190 | /* | |
191 | * Walk the list: Just grab the head because the | |
192 | * detach_region removed the previous head. | |
193 | */ | |
4be44fcd LB |
194 | region_obj = |
195 | handler_obj->address_space.region_list; | |
1da177e4 LT |
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 | ||
44e6f311 HG |
204 | acpi_os_release_mutex(handler_obj->address_space. |
205 | context_mutex); | |
4be44fcd | 206 | acpi_ut_remove_reference(handler_obj); |
1da177e4 LT |
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 | ||
4be44fcd | 218 | ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
b229cf92 | 219 | "Unable to remove address handler %p for %s(%X), DevNode %p, obj %p\n", |
4be44fcd LB |
220 | handler, acpi_ut_get_region_name(space_id), space_id, |
221 | node, obj_desc)); | |
1da177e4 LT |
222 | |
223 | status = AE_NOT_EXIST; | |
224 | ||
10622bf8 | 225 | unlock_and_exit: |
4be44fcd LB |
226 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
227 | return_ACPI_STATUS(status); | |
1da177e4 | 228 | } |
1da177e4 | 229 | |
8313524a | 230 | ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler) |