1 /******************************************************************************
3 * Module Name: evregion - ACPI Address_space (Op_region) handler dispatch
6 *****************************************************************************/
9 * Copyright (C) 2000, 2001 R. Byron Moore
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #define _COMPONENT ACPI_EVENTS
30 MODULE_NAME ("evregion")
33 /**************************************************************************
35 * FUNCTION: Acpi_ev_install_default_address_space_handlers
41 * DESCRIPTION: Installs the core subsystem address space handlers.
43 *************************************************************************/
46 acpi_ev_install_default_address_space_handlers (
53 * All address spaces (PCI Config, EC, SMBus) are scope dependent
54 * and registration must occur for a specific device. In the case
55 * system memory and IO address spaces there is currently no device
56 * associated with the address space. For these we use the root.
57 * We install the default PCI config space handler at the root so
58 * that this space is immediately available even though the we have
59 * not enumerated all the PCI Root Buses yet. This is to conform
60 * to the ACPI specification which states that the PCI config
61 * space must be always available -- even though we are nowhere
62 * near ready to find the PCI root buses at this point.
64 * NOTE: We ignore AE_EXIST because this means that a handler has
65 * already been installed (via Acpi_install_address_space_handler)
68 status
= acpi_install_address_space_handler (acpi_gbl_root_node
,
69 ADDRESS_SPACE_SYSTEM_MEMORY
,
70 ACPI_DEFAULT_HANDLER
, NULL
, NULL
);
71 if ((ACPI_FAILURE (status
)) &&
72 (status
!= AE_EXIST
)) {
76 status
= acpi_install_address_space_handler (acpi_gbl_root_node
,
77 ADDRESS_SPACE_SYSTEM_IO
,
78 ACPI_DEFAULT_HANDLER
, NULL
, NULL
);
79 if ((ACPI_FAILURE (status
)) &&
80 (status
!= AE_EXIST
)) {
84 status
= acpi_install_address_space_handler (acpi_gbl_root_node
,
85 ADDRESS_SPACE_PCI_CONFIG
,
86 ACPI_DEFAULT_HANDLER
, NULL
, NULL
);
87 if ((ACPI_FAILURE (status
)) &&
88 (status
!= AE_EXIST
)) {
97 /* TBD: [Restructure] Move elsewhere */
99 /**************************************************************************
101 * FUNCTION: Acpi_ev_execute_reg_method
103 * PARAMETERS: Region_obj - Object structure
104 * Function - On (1) or Off (0)
108 * DESCRIPTION: Execute _REG method for a region
110 *************************************************************************/
113 acpi_ev_execute_reg_method (
114 ACPI_OPERAND_OBJECT
*region_obj
,
117 ACPI_OPERAND_OBJECT
*params
[3];
118 ACPI_OPERAND_OBJECT space_id_desc
;
119 ACPI_OPERAND_OBJECT function_desc
;
123 if (region_obj
->region
.extra
->extra
.method_REG
== NULL
) {
128 * _REG method has two arguments
129 * Arg0: Integer: Operation region space ID
130 * Same value as Region_obj->Region.Space_id
131 * Arg1: Integer: connection status
132 * 1 for connecting the handler,
133 * 0 for disconnecting the handler
134 * Passed as a parameter
137 acpi_cm_init_static_object (&space_id_desc
);
138 acpi_cm_init_static_object (&function_desc
);
141 * Method requires two parameters.
143 params
[0] = &space_id_desc
;
144 params
[1] = &function_desc
;
148 * Set up the parameter objects
150 space_id_desc
.common
.type
= ACPI_TYPE_INTEGER
;
151 space_id_desc
.integer
.value
= region_obj
->region
.space_id
;
153 function_desc
.common
.type
= ACPI_TYPE_INTEGER
;
154 function_desc
.integer
.value
= function
;
157 * Execute the method, no return value
159 status
= acpi_ns_evaluate_by_handle (region_obj
->region
.extra
->extra
.method_REG
, params
, NULL
);
164 /**************************************************************************
166 * FUNCTION: Acpi_ev_address_space_dispatch
168 * PARAMETERS: Region_obj - internal region object
169 * Space_id - ID of the address space (0-255)
170 * Function - Read or Write operation
171 * Address - Where in the space to read or write
172 * Bit_width - Field width in bits (8, 16, or 32)
173 * Value - Pointer to in or out value
177 * DESCRIPTION: Dispatch an address space or operation region access to
178 * a previously installed handler.
180 *************************************************************************/
183 acpi_ev_address_space_dispatch (
184 ACPI_OPERAND_OBJECT
*region_obj
,
186 ACPI_PHYSICAL_ADDRESS address
,
191 ADDRESS_SPACE_HANDLER handler
;
192 ADDRESS_SPACE_SETUP region_setup
;
193 ACPI_OPERAND_OBJECT
*handler_desc
;
194 void *region_context
= NULL
;
198 * Ensure that there is a handler associated with this region
200 handler_desc
= region_obj
->region
.addr_handler
;
202 return(AE_NOT_EXIST
);
206 * It may be the case that the region has never been initialized
207 * Some types of regions require special init code
209 if (!(region_obj
->region
.flags
& AOPOBJ_INITIALIZED
)) {
211 * This region has not been initialized yet, do it
213 region_setup
= handler_desc
->addr_handler
.setup
;
216 * Bad news, no init routine and not init'd
218 return (AE_UNKNOWN_STATUS
);
222 * We must exit the interpreter because the region setup will potentially
223 * execute control methods
225 acpi_aml_exit_interpreter ();
227 status
= region_setup (region_obj
, ACPI_REGION_ACTIVATE
,
228 handler_desc
->addr_handler
.context
,
231 /* Re-enter the interpreter */
233 acpi_aml_enter_interpreter ();
236 * Init routine may fail
238 if (ACPI_FAILURE (status
)) {
242 region_obj
->region
.flags
|= AOPOBJ_INITIALIZED
;
245 * Save the returned context for use in all accesses to
246 * this particular region.
248 region_obj
->region
.extra
->extra
.region_context
= region_context
;
252 * We have everything we need, begin the process
254 handler
= handler_desc
->addr_handler
.handler
;
256 if (!(handler_desc
->addr_handler
.flags
& ADDR_HANDLER_DEFAULT_INSTALLED
)) {
258 * For handlers other than the default (supplied) handlers, we must
259 * exit the interpreter because the handler *might* block -- we don't
260 * know what it will do, so we can't hold the lock on the intepreter.
262 acpi_aml_exit_interpreter();
266 * Invoke the handler.
268 status
= handler (function
, address
, bit_width
, value
,
269 handler_desc
->addr_handler
.context
,
270 region_obj
->region
.extra
->extra
.region_context
);
273 if (!(handler_desc
->addr_handler
.flags
& ADDR_HANDLER_DEFAULT_INSTALLED
)) {
274 /* We just returned from a non-default handler, we must re-enter the
277 acpi_aml_enter_interpreter ();
283 /******************************************************************************
285 * FUNCTION: Acpi_ev_disassociate_region_from_handler
287 * PARAMETERS: Region_obj - Region Object
288 * Acpi_ns_is_locked - Namespace Region Already Locked?
292 * DESCRIPTION: Break the association between the handler and the region
293 * this is a two way association.
295 ******************************************************************************/
298 acpi_ev_disassociate_region_from_handler(
299 ACPI_OPERAND_OBJECT
*region_obj
,
300 u8 acpi_ns_is_locked
)
302 ACPI_OPERAND_OBJECT
*handler_obj
;
303 ACPI_OPERAND_OBJECT
*obj_desc
;
304 ACPI_OPERAND_OBJECT
**last_obj_ptr
;
305 ADDRESS_SPACE_SETUP region_setup
;
306 void *region_context
;
310 region_context
= region_obj
->region
.extra
->extra
.region_context
;
313 * Get the address handler from the region object
316 handler_obj
= region_obj
->region
.addr_handler
;
319 * This region has no handler, all done
326 * Find this region in the handler's list
329 obj_desc
= handler_obj
->addr_handler
.region_list
;
330 last_obj_ptr
= &handler_obj
->addr_handler
.region_list
;
334 * See if this is the one
336 if (obj_desc
== region_obj
) {
338 * This is it, remove it from the handler's list
340 *last_obj_ptr
= obj_desc
->region
.next
;
341 obj_desc
->region
.next
= NULL
; /* Must clear field */
343 if (acpi_ns_is_locked
) {
344 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE
);
348 * Now stop region accesses by executing the _REG method
350 acpi_ev_execute_reg_method (region_obj
, 0);
352 if (acpi_ns_is_locked
) {
353 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE
);
357 * Call the setup handler with the deactivate notification
359 region_setup
= handler_obj
->addr_handler
.setup
;
360 status
= region_setup (region_obj
, ACPI_REGION_DEACTIVATE
,
361 handler_obj
->addr_handler
.context
,
365 * Init routine may fail, Just ignore errors
368 region_obj
->region
.flags
&= ~(AOPOBJ_INITIALIZED
);
371 * Remove handler reference in the region
373 * NOTE: this doesn't mean that the region goes away
374 * The region is just inaccessible as indicated to
377 * If the region is on the handler's list
378 * this better be the region's handler
380 ACPI_ASSERT (region_obj
->region
.addr_handler
== handler_obj
);
382 region_obj
->region
.addr_handler
= NULL
;
386 } /* found the right handler */
389 * Move through the linked list of handlers
391 last_obj_ptr
= &obj_desc
->region
.next
;
392 obj_desc
= obj_desc
->region
.next
;
396 * If we get here, the region was not in the handler's region list
402 /******************************************************************************
404 * FUNCTION: Acpi_ev_associate_region_and_handler
406 * PARAMETERS: Handler_obj - Handler Object
407 * Region_obj - Region Object
408 * Acpi_ns_is_locked - Namespace Region Already Locked?
412 * DESCRIPTION: Create the association between the handler and the region
413 * this is a two way association.
415 ******************************************************************************/
418 acpi_ev_associate_region_and_handler (
419 ACPI_OPERAND_OBJECT
*handler_obj
,
420 ACPI_OPERAND_OBJECT
*region_obj
,
421 u8 acpi_ns_is_locked
)
426 ACPI_ASSERT (region_obj
->region
.space_id
== handler_obj
->addr_handler
.space_id
);
427 ACPI_ASSERT (region_obj
->region
.addr_handler
== 0);
430 * Link this region to the front of the handler's list
433 region_obj
->region
.next
= handler_obj
->addr_handler
.region_list
;
434 handler_obj
->addr_handler
.region_list
= region_obj
;
437 * set the region's handler
441 Handler_obj->Common.Reference_count =
442 (u16) (Handler_obj->Common.Reference_count +
443 Region_obj->Common.Reference_count - 1);
445 region_obj
->region
.addr_handler
= handler_obj
;
448 * Last thing, tell all users that this region is usable
450 if (acpi_ns_is_locked
) {
451 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE
);
454 status
= acpi_ev_execute_reg_method (region_obj
, 1);
456 if (acpi_ns_is_locked
) {
457 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE
);
464 /****************************************************************************
466 * FUNCTION: Acpi_ev_addr_handler_helper
468 * PARAMETERS: Handle - Node to be dumped
469 * Level - Nesting level of the handle
470 * Context - Passed into Acpi_ns_walk_namespace
472 * DESCRIPTION: This routine checks to see if the object is a Region if it
473 * is then the address handler is installed in it.
475 * If the Object is a Device, and the device has a handler of
476 * the same type then the search is terminated in that branch.
478 * This is because the existing handler is closer in proximity
479 * to any more regions than the one we are trying to install.
481 ***************************************************************************/
484 acpi_ev_addr_handler_helper (
485 ACPI_HANDLE obj_handle
,
490 ACPI_OPERAND_OBJECT
*handler_obj
;
491 ACPI_OPERAND_OBJECT
*tmp_obj
;
492 ACPI_OPERAND_OBJECT
*obj_desc
;
493 ACPI_NAMESPACE_NODE
*node
;
497 handler_obj
= (ACPI_OPERAND_OBJECT
*) context
;
499 /* Parameter validation */
505 /* Convert and validate the device handle */
507 node
= acpi_ns_convert_handle_to_entry (obj_handle
);
509 return (AE_BAD_PARAMETER
);
513 * We only care about regions.and objects
514 * that can have address handlers
517 if ((node
->type
!= ACPI_TYPE_DEVICE
) &&
518 (node
->type
!= ACPI_TYPE_REGION
) &&
519 (node
!= acpi_gbl_root_node
)) {
523 /* Check for an existing internal object */
525 obj_desc
= acpi_ns_get_attached_object ((ACPI_HANDLE
) node
);
528 * The object DNE, we don't care about it
534 * Devices are handled different than regions
536 if (IS_THIS_OBJECT_TYPE (obj_desc
, ACPI_TYPE_DEVICE
)) {
538 * See if this guy has any handlers
540 tmp_obj
= obj_desc
->device
.addr_handler
;
543 * Now let's see if it's for the same address space.
545 if (tmp_obj
->addr_handler
.space_id
== handler_obj
->addr_handler
.space_id
) {
547 * It's for the same address space
550 * Since the object we found it on was a device, then it
551 * means that someone has already installed a handler for
552 * the branch of the namespace from this device on. Just
553 * bail out telling the walk routine to not traverse this
554 * branch. This preserves the scoping rule for handlers.
556 return (AE_CTRL_DEPTH
);
560 * Move through the linked list of handlers
562 tmp_obj
= tmp_obj
->addr_handler
.next
;
566 * As long as the device didn't have a handler for this
567 * space we don't care about it. We just ignore it and
574 * Only here if it was a region
576 ACPI_ASSERT (obj_desc
->common
.type
== ACPI_TYPE_REGION
);
578 if (obj_desc
->region
.space_id
!= handler_obj
->addr_handler
.space_id
) {
580 * This region is for a different address space
587 * Now we have a region and it is for the handler's address
590 * First disconnect region for any previous handler (if any)
592 acpi_ev_disassociate_region_from_handler (obj_desc
, FALSE
);
595 * Then connect the region to the new handler
597 status
= acpi_ev_associate_region_and_handler (handler_obj
, obj_desc
, FALSE
);