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
33 #define _COMPONENT ACPI_EVENTS
34 MODULE_NAME ("evregion")
37 /**************************************************************************
39 * FUNCTION: Acpi_ev_install_default_address_space_handlers
45 * DESCRIPTION: Installs the core subsystem address space handlers.
47 *************************************************************************/
50 acpi_ev_install_default_address_space_handlers (
57 * All address spaces (PCI Config, EC, SMBus) are scope dependent
58 * and registration must occur for a specific device. In the case
59 * system memory and IO address spaces there is currently no device
60 * associated with the address space. For these we use the root.
61 * We install the default PCI config space handler at the root so
62 * that this space is immediately available even though the we have
63 * not enumerated all the PCI Root Buses yet. This is to conform
64 * to the ACPI specification which states that the PCI config
65 * space must be always available -- even though we are nowhere
66 * near ready to find the PCI root buses at this point.
68 * NOTE: We ignore AE_EXIST because this means that a handler has
69 * already been installed (via Acpi_install_address_space_handler)
72 status
= acpi_install_address_space_handler (acpi_gbl_root_node
,
73 ADDRESS_SPACE_SYSTEM_MEMORY
,
74 ACPI_DEFAULT_HANDLER
, NULL
, NULL
);
75 if ((ACPI_FAILURE (status
)) &&
76 (status
!= AE_EXIST
)) {
80 status
= acpi_install_address_space_handler (acpi_gbl_root_node
,
81 ADDRESS_SPACE_SYSTEM_IO
,
82 ACPI_DEFAULT_HANDLER
, NULL
, NULL
);
83 if ((ACPI_FAILURE (status
)) &&
84 (status
!= AE_EXIST
)) {
88 status
= acpi_install_address_space_handler (acpi_gbl_root_node
,
89 ADDRESS_SPACE_PCI_CONFIG
,
90 ACPI_DEFAULT_HANDLER
, NULL
, NULL
);
91 if ((ACPI_FAILURE (status
)) &&
92 (status
!= AE_EXIST
)) {
101 /* TBD: [Restructure] Move elsewhere */
103 /**************************************************************************
105 * FUNCTION: Acpi_ev_execute_reg_method
107 * PARAMETERS: Region_obj - Object structure
108 * Function - On (1) or Off (0)
112 * DESCRIPTION: Execute _REG method for a region
114 *************************************************************************/
117 acpi_ev_execute_reg_method (
118 ACPI_OPERAND_OBJECT
*region_obj
,
121 ACPI_OPERAND_OBJECT
*params
[3];
122 ACPI_OPERAND_OBJECT space_id_desc
;
123 ACPI_OPERAND_OBJECT function_desc
;
127 if (region_obj
->region
.extra
->extra
.method_REG
== NULL
) {
132 * _REG method has two arguments
133 * Arg0: Integer: Operation region space ID
134 * Same value as Region_obj->Region.Space_id
135 * Arg1: Integer: connection status
136 * 1 for connecting the handler,
137 * 0 for disconnecting the handler
138 * Passed as a parameter
141 acpi_cm_init_static_object (&space_id_desc
);
142 acpi_cm_init_static_object (&function_desc
);
145 * Method requires two parameters.
147 params
[0] = &space_id_desc
;
148 params
[1] = &function_desc
;
152 * Set up the parameter objects
154 space_id_desc
.common
.type
= ACPI_TYPE_INTEGER
;
155 space_id_desc
.integer
.value
= region_obj
->region
.space_id
;
157 function_desc
.common
.type
= ACPI_TYPE_INTEGER
;
158 function_desc
.integer
.value
= function
;
161 * Execute the method, no return value
163 status
= acpi_ns_evaluate_by_handle (region_obj
->region
.extra
->extra
.method_REG
, params
, NULL
);
168 /**************************************************************************
170 * FUNCTION: Acpi_ev_address_space_dispatch
172 * PARAMETERS: Region_obj - internal region object
173 * Space_id - ID of the address space (0-255)
174 * Function - Read or Write operation
175 * Address - Where in the space to read or write
176 * Bit_width - Field width in bits (8, 16, or 32)
177 * Value - Pointer to in or out value
181 * DESCRIPTION: Dispatch an address space or operation region access to
182 * a previously installed handler.
184 *************************************************************************/
187 acpi_ev_address_space_dispatch (
188 ACPI_OPERAND_OBJECT
*region_obj
,
190 ACPI_PHYSICAL_ADDRESS address
,
195 ADDRESS_SPACE_HANDLER handler
;
196 ADDRESS_SPACE_SETUP region_setup
;
197 ACPI_OPERAND_OBJECT
*handler_desc
;
198 void *region_context
= NULL
;
202 * Ensure that there is a handler associated with this region
204 handler_desc
= region_obj
->region
.addr_handler
;
206 return(AE_NOT_EXIST
);
210 * It may be the case that the region has never been initialized
211 * Some types of regions require special init code
213 if (!(region_obj
->region
.flags
& AOPOBJ_INITIALIZED
)) {
215 * This region has not been initialized yet, do it
217 region_setup
= handler_desc
->addr_handler
.setup
;
220 * Bad news, no init routine and not init'd
222 return (AE_UNKNOWN_STATUS
);
226 * We must exit the interpreter because the region setup will potentially
227 * execute control methods
229 acpi_aml_exit_interpreter ();
231 status
= region_setup (region_obj
, ACPI_REGION_ACTIVATE
,
232 handler_desc
->addr_handler
.context
,
235 /* Re-enter the interpreter */
237 acpi_aml_enter_interpreter ();
240 * Init routine may fail
242 if (ACPI_FAILURE (status
)) {
246 region_obj
->region
.flags
|= AOPOBJ_INITIALIZED
;
249 * Save the returned context for use in all accesses to
250 * this particular region.
252 region_obj
->region
.extra
->extra
.region_context
= region_context
;
256 * We have everything we need, begin the process
258 handler
= handler_desc
->addr_handler
.handler
;
260 if (!(handler_desc
->addr_handler
.flags
& ADDR_HANDLER_DEFAULT_INSTALLED
)) {
262 * For handlers other than the default (supplied) handlers, we must
263 * exit the interpreter because the handler *might* block -- we don't
264 * know what it will do, so we can't hold the lock on the intepreter.
266 acpi_aml_exit_interpreter();
270 * Invoke the handler.
272 status
= handler (function
, address
, bit_width
, value
,
273 handler_desc
->addr_handler
.context
,
274 region_obj
->region
.extra
->extra
.region_context
);
277 if (!(handler_desc
->addr_handler
.flags
& ADDR_HANDLER_DEFAULT_INSTALLED
)) {
278 /* We just returned from a non-default handler, we must re-enter the
281 acpi_aml_enter_interpreter ();
287 /******************************************************************************
289 * FUNCTION: Acpi_ev_disassociate_region_from_handler
291 * PARAMETERS: Region_obj - Region Object
292 * Acpi_ns_is_locked - Namespace Region Already Locked?
296 * DESCRIPTION: Break the association between the handler and the region
297 * this is a two way association.
299 ******************************************************************************/
302 acpi_ev_disassociate_region_from_handler(
303 ACPI_OPERAND_OBJECT
*region_obj
,
304 u8 acpi_ns_is_locked
)
306 ACPI_OPERAND_OBJECT
*handler_obj
;
307 ACPI_OPERAND_OBJECT
*obj_desc
;
308 ACPI_OPERAND_OBJECT
**last_obj_ptr
;
309 ADDRESS_SPACE_SETUP region_setup
;
310 void *region_context
;
314 region_context
= region_obj
->region
.extra
->extra
.region_context
;
317 * Get the address handler from the region object
320 handler_obj
= region_obj
->region
.addr_handler
;
323 * This region has no handler, all done
330 * Find this region in the handler's list
333 obj_desc
= handler_obj
->addr_handler
.region_list
;
334 last_obj_ptr
= &handler_obj
->addr_handler
.region_list
;
338 * See if this is the one
340 if (obj_desc
== region_obj
) {
342 * This is it, remove it from the handler's list
344 *last_obj_ptr
= obj_desc
->region
.next
;
345 obj_desc
->region
.next
= NULL
; /* Must clear field */
347 if (acpi_ns_is_locked
) {
348 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE
);
352 * Now stop region accesses by executing the _REG method
354 acpi_ev_execute_reg_method (region_obj
, 0);
356 if (acpi_ns_is_locked
) {
357 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE
);
361 * Call the setup handler with the deactivate notification
363 region_setup
= handler_obj
->addr_handler
.setup
;
364 status
= region_setup (region_obj
, ACPI_REGION_DEACTIVATE
,
365 handler_obj
->addr_handler
.context
,
369 * Init routine may fail, Just ignore errors
372 region_obj
->region
.flags
&= ~(AOPOBJ_INITIALIZED
);
375 * Remove handler reference in the region
377 * NOTE: this doesn't mean that the region goes away
378 * The region is just inaccessible as indicated to
381 * If the region is on the handler's list
382 * this better be the region's handler
384 ACPI_ASSERT (region_obj
->region
.addr_handler
== handler_obj
);
386 region_obj
->region
.addr_handler
= NULL
;
390 } /* found the right handler */
393 * Move through the linked list of handlers
395 last_obj_ptr
= &obj_desc
->region
.next
;
396 obj_desc
= obj_desc
->region
.next
;
400 * If we get here, the region was not in the handler's region list
406 /******************************************************************************
408 * FUNCTION: Acpi_ev_associate_region_and_handler
410 * PARAMETERS: Handler_obj - Handler Object
411 * Region_obj - Region Object
412 * Acpi_ns_is_locked - Namespace Region Already Locked?
416 * DESCRIPTION: Create the association between the handler and the region
417 * this is a two way association.
419 ******************************************************************************/
422 acpi_ev_associate_region_and_handler (
423 ACPI_OPERAND_OBJECT
*handler_obj
,
424 ACPI_OPERAND_OBJECT
*region_obj
,
425 u8 acpi_ns_is_locked
)
430 ACPI_ASSERT (region_obj
->region
.space_id
== handler_obj
->addr_handler
.space_id
);
431 ACPI_ASSERT (region_obj
->region
.addr_handler
== 0);
434 * Link this region to the front of the handler's list
437 region_obj
->region
.next
= handler_obj
->addr_handler
.region_list
;
438 handler_obj
->addr_handler
.region_list
= region_obj
;
441 * set the region's handler
445 Handler_obj->Common.Reference_count =
446 (u16) (Handler_obj->Common.Reference_count +
447 Region_obj->Common.Reference_count - 1);
449 region_obj
->region
.addr_handler
= handler_obj
;
452 * Last thing, tell all users that this region is usable
454 if (acpi_ns_is_locked
) {
455 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE
);
458 status
= acpi_ev_execute_reg_method (region_obj
, 1);
460 if (acpi_ns_is_locked
) {
461 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE
);
468 /****************************************************************************
470 * FUNCTION: Acpi_ev_addr_handler_helper
472 * PARAMETERS: Handle - Node to be dumped
473 * Level - Nesting level of the handle
474 * Context - Passed into Acpi_ns_walk_namespace
476 * DESCRIPTION: This routine checks to see if the object is a Region if it
477 * is then the address handler is installed in it.
479 * If the Object is a Device, and the device has a handler of
480 * the same type then the search is terminated in that branch.
482 * This is because the existing handler is closer in proximity
483 * to any more regions than the one we are trying to install.
485 ***************************************************************************/
488 acpi_ev_addr_handler_helper (
489 ACPI_HANDLE obj_handle
,
494 ACPI_OPERAND_OBJECT
*handler_obj
;
495 ACPI_OPERAND_OBJECT
*tmp_obj
;
496 ACPI_OPERAND_OBJECT
*obj_desc
;
497 ACPI_NAMESPACE_NODE
*node
;
501 handler_obj
= (ACPI_OPERAND_OBJECT
*) context
;
503 /* Parameter validation */
509 /* Convert and validate the device handle */
511 node
= acpi_ns_convert_handle_to_entry (obj_handle
);
513 return (AE_BAD_PARAMETER
);
517 * We only care about regions.and objects
518 * that can have address handlers
521 if ((node
->type
!= ACPI_TYPE_DEVICE
) &&
522 (node
->type
!= ACPI_TYPE_REGION
) &&
523 (node
!= acpi_gbl_root_node
)) {
527 /* Check for an existing internal object */
529 obj_desc
= acpi_ns_get_attached_object ((ACPI_HANDLE
) node
);
532 * The object DNE, we don't care about it
538 * Devices are handled different than regions
540 if (IS_THIS_OBJECT_TYPE (obj_desc
, ACPI_TYPE_DEVICE
)) {
542 * See if this guy has any handlers
544 tmp_obj
= obj_desc
->device
.addr_handler
;
547 * Now let's see if it's for the same address space.
549 if (tmp_obj
->addr_handler
.space_id
== handler_obj
->addr_handler
.space_id
) {
551 * It's for the same address space
554 * Since the object we found it on was a device, then it
555 * means that someone has already installed a handler for
556 * the branch of the namespace from this device on. Just
557 * bail out telling the walk routine to not traverse this
558 * branch. This preserves the scoping rule for handlers.
560 return (AE_CTRL_DEPTH
);
564 * Move through the linked list of handlers
566 tmp_obj
= tmp_obj
->addr_handler
.next
;
570 * As long as the device didn't have a handler for this
571 * space we don't care about it. We just ignore it and
578 * Only here if it was a region
580 ACPI_ASSERT (obj_desc
->common
.type
== ACPI_TYPE_REGION
);
582 if (obj_desc
->region
.space_id
!= handler_obj
->addr_handler
.space_id
) {
584 * This region is for a different address space
591 * Now we have a region and it is for the handler's address
594 * First disconnect region for any previous handler (if any)
596 acpi_ev_disassociate_region_from_handler (obj_desc
, FALSE
);
599 * Then connect the region to the new handler
601 status
= acpi_ev_associate_region_and_handler (handler_obj
, obj_desc
, FALSE
);