- Kai Germaschewski: ISDN update (including Makefiles)
[davej-history.git] / drivers / acpi / events / evxfregn.c
blobade6f08b950ba36906ddee09d85490c0dbe666d0
1 /******************************************************************************
3 * Module Name: evxfregn - External Interfaces, ACPI Operation Regions and
4 * Address Spaces.
5 * $Revision: 24 $
7 *****************************************************************************/
9 /*
10 * Copyright (C) 2000 R. Byron Moore
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "acpi.h"
29 #include "achware.h"
30 #include "acnamesp.h"
31 #include "acevents.h"
32 #include "amlcode.h"
33 #include "acinterp.h"
35 #define _COMPONENT EVENT_HANDLING
36 MODULE_NAME ("evxfregn")
39 /******************************************************************************
41 * FUNCTION: Acpi_install_address_space_handler
43 * PARAMETERS: Device - Handle for the device
44 * Space_id - The address space ID
45 * Handler - Address of the handler
46 * Setup - Address of the setup function
47 * Context - Value passed to the handler on each access
49 * RETURN: Status
51 * DESCRIPTION: Install a handler for all Op_regions of a given Space_id.
53 ******************************************************************************/
55 ACPI_STATUS
56 acpi_install_address_space_handler (
57 ACPI_HANDLE device,
58 ACPI_ADDRESS_SPACE_TYPE space_id,
59 ADDRESS_SPACE_HANDLER handler,
60 ADDRESS_SPACE_SETUP setup,
61 void *context)
63 ACPI_OPERAND_OBJECT *obj_desc;
64 ACPI_OPERAND_OBJECT *handler_obj;
65 ACPI_NAMESPACE_NODE *node;
66 ACPI_STATUS status = AE_OK;
67 OBJECT_TYPE_INTERNAL type;
68 u16 flags = 0;
71 /* Parameter validation */
73 if ((!device) ||
74 ((!handler) && (handler != ACPI_DEFAULT_HANDLER)) ||
75 (space_id > ACPI_MAX_ADDRESS_SPACE))
77 return (AE_BAD_PARAMETER);
80 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
82 /* Convert and validate the device handle */
84 node = acpi_ns_convert_handle_to_entry (device);
85 if (!node) {
86 status = AE_BAD_PARAMETER;
87 goto unlock_and_exit;
91 * This registration is valid for only the types below
92 * and the root. This is where the default handlers
93 * get placed.
96 if ((node->type != ACPI_TYPE_DEVICE) &&
97 (node->type != ACPI_TYPE_PROCESSOR) &&
98 (node->type != ACPI_TYPE_THERMAL) &&
99 (node != acpi_gbl_root_node))
101 status = AE_BAD_PARAMETER;
102 goto unlock_and_exit;
105 if (handler == ACPI_DEFAULT_HANDLER) {
106 flags = ADDR_HANDLER_DEFAULT_INSTALLED;
108 switch (space_id)
110 case ADDRESS_SPACE_SYSTEM_MEMORY:
111 handler = acpi_aml_system_memory_space_handler;
112 setup = acpi_ev_system_memory_region_setup;
113 break;
115 case ADDRESS_SPACE_SYSTEM_IO:
116 handler = acpi_aml_system_io_space_handler;
117 setup = acpi_ev_io_space_region_setup;
118 break;
120 case ADDRESS_SPACE_PCI_CONFIG:
121 handler = acpi_aml_pci_config_space_handler;
122 setup = acpi_ev_pci_config_region_setup;
123 break;
125 default:
126 status = AE_NOT_EXIST;
127 goto unlock_and_exit;
128 break;
133 * If the caller hasn't specified a setup routine, use the default
135 if (!setup) {
136 setup = acpi_ev_default_region_setup;
140 * Check for an existing internal object
143 obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node);
144 if (obj_desc) {
146 * The object exists.
147 * Make sure the handler is not already installed.
150 /* check the address handler the user requested */
152 handler_obj = obj_desc->device.addr_handler;
153 while (handler_obj) {
155 * We have an Address handler, see if user requested this
156 * address space.
158 if(handler_obj->addr_handler.space_id == space_id) {
159 status = AE_EXIST;
160 goto unlock_and_exit;
164 * Move through the linked list of handlers
166 handler_obj = handler_obj->addr_handler.next;
170 else {
171 /* Obj_desc does not exist, create one */
173 if (node->type == ACPI_TYPE_ANY) {
174 type = ACPI_TYPE_DEVICE;
177 else {
178 type = node->type;
181 obj_desc = acpi_cm_create_internal_object (type);
182 if (!obj_desc) {
183 status = AE_NO_MEMORY;
184 goto unlock_and_exit;
187 /* Init new descriptor */
189 obj_desc->common.type = (u8) type;
191 /* Attach the new object to the Node */
193 status = acpi_ns_attach_object (node, obj_desc, (u8) type);
194 if (ACPI_FAILURE (status)) {
195 acpi_cm_remove_reference (obj_desc);
196 goto unlock_and_exit;
201 * Now we can install the handler
203 * At this point we know that there is no existing handler.
204 * So, we just allocate the object for the handler and link it
205 * into the list.
207 handler_obj = acpi_cm_create_internal_object (INTERNAL_TYPE_ADDRESS_HANDLER);
208 if (!handler_obj) {
209 status = AE_NO_MEMORY;
210 goto unlock_and_exit;
213 handler_obj->addr_handler.space_id = (u8) space_id;
214 handler_obj->addr_handler.hflags = flags;
215 handler_obj->addr_handler.next = obj_desc->device.addr_handler;
216 handler_obj->addr_handler.region_list = NULL;
217 handler_obj->addr_handler.node = node;
218 handler_obj->addr_handler.handler = handler;
219 handler_obj->addr_handler.context = context;
220 handler_obj->addr_handler.setup = setup;
223 * Now walk the namespace finding all of the regions this
224 * handler will manage.
226 * We start at the device and search the branch toward
227 * the leaf nodes until either the leaf is encountered or
228 * a device is detected that has an address handler of the
229 * same type.
231 * In either case we back up and search down the remainder
232 * of the branch
234 status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, device,
235 ACPI_UINT32_MAX, NS_WALK_UNLOCK,
236 acpi_ev_addr_handler_helper,
237 handler_obj, NULL);
240 * Place this handler 1st on the list
243 handler_obj->common.reference_count =
244 (u16) (handler_obj->common.reference_count +
245 obj_desc->common.reference_count - 1);
246 obj_desc->device.addr_handler = handler_obj;
249 unlock_and_exit:
250 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
251 return (status);
255 /******************************************************************************
257 * FUNCTION: Acpi_remove_address_space_handler
259 * PARAMETERS: Space_id - The address space ID
260 * Handler - Address of the handler
262 * RETURN: Status
264 * DESCRIPTION: Install a handler for accesses on an Operation Region
266 ******************************************************************************/
268 ACPI_STATUS
269 acpi_remove_address_space_handler (
270 ACPI_HANDLE device,
271 ACPI_ADDRESS_SPACE_TYPE space_id,
272 ADDRESS_SPACE_HANDLER handler)
274 ACPI_OPERAND_OBJECT *obj_desc;
275 ACPI_OPERAND_OBJECT *handler_obj;
276 ACPI_OPERAND_OBJECT *region_obj;
277 ACPI_OPERAND_OBJECT **last_obj_ptr;
278 ACPI_NAMESPACE_NODE *node;
279 ACPI_STATUS status = AE_OK;
282 /* Parameter validation */
284 if ((!device) ||
285 ((!handler) && (handler != ACPI_DEFAULT_HANDLER)) ||
286 (space_id > ACPI_MAX_ADDRESS_SPACE))
288 return (AE_BAD_PARAMETER);
291 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
293 /* Convert and validate the device handle */
295 node = acpi_ns_convert_handle_to_entry (device);
296 if (!node) {
297 status = AE_BAD_PARAMETER;
298 goto unlock_and_exit;
302 /* Make sure the internal object exists */
304 obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node);
305 if (!obj_desc) {
307 * The object DNE.
309 status = AE_NOT_EXIST;
310 goto unlock_and_exit;
314 * find the address handler the user requested
317 handler_obj = obj_desc->device.addr_handler;
318 last_obj_ptr = &obj_desc->device.addr_handler;
319 while (handler_obj) {
321 * We have a handler, see if user requested this one
324 if(handler_obj->addr_handler.space_id == space_id) {
326 * Got it, first dereference this in the Regions
328 region_obj = handler_obj->addr_handler.region_list;
330 /* Walk the handler's region list */
332 while (region_obj) {
334 * First disassociate the handler from the region.
336 * NOTE: this doesn't mean that the region goes away
337 * The region is just inaccessible as indicated to
338 * the _REG method
340 acpi_ev_disassociate_region_from_handler(region_obj);
343 * Walk the list, since we took the first region and it
344 * was removed from the list by the dissassociate call
345 * we just get the first item on the list again
347 region_obj = handler_obj->addr_handler.region_list;
352 * Remove this Handler object from the list
354 *last_obj_ptr = handler_obj->addr_handler.next;
357 * Now we can delete the handler object
359 acpi_cm_remove_reference (handler_obj);
360 acpi_cm_remove_reference (handler_obj);
362 goto unlock_and_exit;
366 * Move through the linked list of handlers
368 last_obj_ptr = &handler_obj->addr_handler.next;
369 handler_obj = handler_obj->addr_handler.next;
374 * The handler does not exist
376 status = AE_NOT_EXIST;
379 unlock_and_exit:
380 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
381 return (status);