1 /******************************************************************************
3 * Module Name: evregion - ACPI Address_space (Op_region) handler dispatch
6 *****************************************************************************/
9 * Copyright (C) 2000 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 EVENT_HANDLING
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
)) &&
81 status
= acpi_install_address_space_handler (acpi_gbl_root_node
,
82 ADDRESS_SPACE_SYSTEM_IO
,
83 ACPI_DEFAULT_HANDLER
, NULL
, NULL
);
84 if ((ACPI_FAILURE (status
)) &&
90 status
= acpi_install_address_space_handler (acpi_gbl_root_node
,
91 ADDRESS_SPACE_PCI_CONFIG
,
92 ACPI_DEFAULT_HANDLER
, NULL
, NULL
);
93 if ((ACPI_FAILURE (status
)) &&
104 /* TBD: [Restructure] Move elsewhere */
106 /**************************************************************************
108 * FUNCTION: Acpi_ev_execute_reg_method
110 * PARAMETERS: Region_obj - Object structure
111 * Function - On (1) or Off (0)
115 * DESCRIPTION: Execute _REG method for a region
117 *************************************************************************/
120 acpi_ev_execute_reg_method (
121 ACPI_OPERAND_OBJECT
*region_obj
,
124 ACPI_OPERAND_OBJECT
*params
[3];
125 ACPI_OPERAND_OBJECT space_iD_obj
;
126 ACPI_OPERAND_OBJECT function_obj
;
130 if (region_obj
->region
.extra
->extra
.method_REG
== NULL
) {
135 * _REG method has two arguments
136 * Arg0: Integer: Operation region space ID
137 * Same value as Region_obj->Region.Space_id
138 * Arg1: Integer: connection status
139 * 1 for connecting the handler,
140 * 0 for disconnecting the handler
141 * Passed as a parameter
144 acpi_cm_init_static_object (&space_iD_obj
);
145 acpi_cm_init_static_object (&function_obj
);
148 * Method requires two parameters.
150 params
[0] = &space_iD_obj
;
151 params
[1] = &function_obj
;
155 * Set up the parameter objects
157 space_iD_obj
.common
.type
= ACPI_TYPE_NUMBER
;
158 space_iD_obj
.number
.value
= region_obj
->region
.space_id
;
160 function_obj
.common
.type
= ACPI_TYPE_NUMBER
;
161 function_obj
.number
.value
= function
;
164 * Execute the method, no return value
166 status
= acpi_ns_evaluate_by_handle (region_obj
->region
.extra
->extra
.method_REG
, params
, NULL
);
171 /**************************************************************************
173 * FUNCTION: Acpi_ev_address_space_dispatch
175 * PARAMETERS: Region_obj - internal region object
176 * Space_id - ID of the address space (0-255)
177 * Function - Read or Write operation
178 * Address - Where in the space to read or write
179 * Bit_width - Field width in bits (8, 16, or 32)
180 * Value - Pointer to in or out value
184 * DESCRIPTION: Dispatch an address space or operation region access to
185 * a previously installed handler.
187 *************************************************************************/
190 acpi_ev_address_space_dispatch (
191 ACPI_OPERAND_OBJECT
*region_obj
,
193 ACPI_PHYSICAL_ADDRESS address
,
198 ADDRESS_SPACE_HANDLER handler
;
199 ADDRESS_SPACE_SETUP region_setup
;
200 ACPI_OPERAND_OBJECT
*handler_desc
;
201 void *region_context
= NULL
;
205 * Check for an installed handler
207 handler_desc
= region_obj
->region
.addr_handler
;
210 return(AE_NOT_EXIST
);
214 * It may be the case that the region has never been initialized
215 * Some types of regions require special init code
217 if (!(region_obj
->region
.flags
& AOPOBJ_INITIALIZED
)) {
219 * This region has not been initialized yet, do it
221 region_setup
= handler_desc
->addr_handler
.setup
;
224 * Bad news, no init routine and not init'd
226 return (AE_UNKNOWN_STATUS
);
230 * We must exit the interpreter because the region setup will potentially
231 * execute control methods
233 acpi_aml_exit_interpreter ();
235 status
= region_setup (region_obj
, ACPI_REGION_ACTIVATE
,
236 handler_desc
->addr_handler
.context
,
239 /* Re-enter the interpreter */
241 acpi_aml_enter_interpreter ();
244 * Init routine may fail
246 if (ACPI_FAILURE (status
)) {
250 region_obj
->region
.flags
|= AOPOBJ_INITIALIZED
;
253 * Save the returned context for use in all accesses to
254 * this particular region.
256 region_obj
->region
.extra
->extra
.region_context
= region_context
;
260 * We have everything we need, begin the process
262 handler
= handler_desc
->addr_handler
.handler
;
264 if (!(handler_desc
->addr_handler
.flags
& ADDR_HANDLER_DEFAULT_INSTALLED
)) {
266 * For handlers other than the default (supplied) handlers, we must
267 * exit the interpreter because the handler *might* block -- we don't
268 * know what it will do, so we can't hold the lock on the intepreter.
270 acpi_aml_exit_interpreter();
274 * Invoke the handler.
276 status
= handler (function
, address
, bit_width
, value
,
277 handler_desc
->addr_handler
.context
,
278 region_obj
->region
.extra
->extra
.region_context
);
281 if (!(handler_desc
->addr_handler
.flags
& ADDR_HANDLER_DEFAULT_INSTALLED
)) {
282 /* We just returned from a non-default handler, we must re-enter the
285 acpi_aml_enter_interpreter ();
291 /******************************************************************************
293 * FUNCTION: Acpi_ev_disassociate_region_from_handler
295 * PARAMETERS: Region_obj - Region Object
296 * Acpi_ns_is_locked - Namespace Region Already Locked?
300 * DESCRIPTION: Break the association between the handler and the region
301 * this is a two way association.
303 ******************************************************************************/
306 acpi_ev_disassociate_region_from_handler(
307 ACPI_OPERAND_OBJECT
*region_obj
,
308 u8 acpi_ns_is_locked
)
310 ACPI_OPERAND_OBJECT
*handler_obj
;
311 ACPI_OPERAND_OBJECT
*obj_desc
;
312 ACPI_OPERAND_OBJECT
**last_obj_ptr
;
313 ADDRESS_SPACE_SETUP region_setup
;
314 void *region_context
;
318 region_context
= region_obj
->region
.extra
->extra
.region_context
;
321 * Get the address handler from the region object
324 handler_obj
= region_obj
->region
.addr_handler
;
327 * This region has no handler, all done
334 * Find this region in the handler's list
337 obj_desc
= handler_obj
->addr_handler
.region_list
;
338 last_obj_ptr
= &handler_obj
->addr_handler
.region_list
;
342 * See if this is the one
344 if (obj_desc
== region_obj
) {
346 * This is it, remove it from the handler's list
348 *last_obj_ptr
= obj_desc
->region
.next
;
349 obj_desc
->region
.next
= NULL
; /* Must clear field */
351 if (acpi_ns_is_locked
) {
352 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE
);
356 * Now stop region accesses by executing the _REG method
358 acpi_ev_execute_reg_method (region_obj
, 0);
360 if (acpi_ns_is_locked
) {
361 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE
);
365 * Call the setup handler with the deactivate notification
367 region_setup
= handler_obj
->addr_handler
.setup
;
368 status
= region_setup (region_obj
, ACPI_REGION_DEACTIVATE
,
369 handler_obj
->addr_handler
.context
,
373 * Init routine may fail, Just ignore errors
376 region_obj
->region
.flags
&= ~(AOPOBJ_INITIALIZED
);
379 * Remove handler reference in the region
381 * NOTE: this doesn't mean that the region goes away
382 * The region is just inaccessible as indicated to
385 * If the region is on the handler's list
386 * this better be the region's handler
388 ACPI_ASSERT (region_obj
->region
.addr_handler
== handler_obj
);
390 region_obj
->region
.addr_handler
= NULL
;
394 } /* found the right handler */
397 * Move through the linked list of handlers
399 last_obj_ptr
= &obj_desc
->region
.next
;
400 obj_desc
= obj_desc
->region
.next
;
404 * If we get here, the region was not in the handler's region list
410 /******************************************************************************
412 * FUNCTION: Acpi_ev_associate_region_and_handler
414 * PARAMETERS: Handler_obj - Handler Object
415 * Region_obj - Region Object
416 * Acpi_ns_is_locked - Namespace Region Already Locked?
420 * DESCRIPTION: Create the association between the handler and the region
421 * this is a two way association.
423 ******************************************************************************/
426 acpi_ev_associate_region_and_handler (
427 ACPI_OPERAND_OBJECT
*handler_obj
,
428 ACPI_OPERAND_OBJECT
*region_obj
,
429 u8 acpi_ns_is_locked
)
434 ACPI_ASSERT (region_obj
->region
.space_id
== handler_obj
->addr_handler
.space_id
);
435 ACPI_ASSERT (region_obj
->region
.addr_handler
== 0);
438 * Link this region to the front of the handler's list
441 region_obj
->region
.next
= handler_obj
->addr_handler
.region_list
;
442 handler_obj
->addr_handler
.region_list
= region_obj
;
445 * set the region's handler
449 Handler_obj->Common.Reference_count =
450 (u16) (Handler_obj->Common.Reference_count +
451 Region_obj->Common.Reference_count - 1);
453 region_obj
->region
.addr_handler
= handler_obj
;
456 * Last thing, tell all users that this region is usable
458 if (acpi_ns_is_locked
) {
459 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE
);
462 status
= acpi_ev_execute_reg_method (region_obj
, 1);
464 if (acpi_ns_is_locked
) {
465 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE
);
472 /****************************************************************************
474 * FUNCTION: Acpi_ev_addr_handler_helper
476 * PARAMETERS: Handle - Node to be dumped
477 * Level - Nesting level of the handle
478 * Context - Passed into Acpi_ns_walk_namespace
480 * DESCRIPTION: This routine checks to see if the object is a Region if it
481 * is then the address handler is installed in it.
483 * If the Object is a Device, and the device has a handler of
484 * the same type then the search is terminated in that branch.
486 * This is because the existing handler is closer in proximity
487 * to any more regions than the one we are trying to install.
489 ***************************************************************************/
492 acpi_ev_addr_handler_helper (
493 ACPI_HANDLE obj_handle
,
498 ACPI_OPERAND_OBJECT
*handler_obj
;
499 ACPI_OPERAND_OBJECT
*tmp_obj
;
500 ACPI_OPERAND_OBJECT
*obj_desc
;
501 ACPI_NAMESPACE_NODE
*node
;
505 handler_obj
= (ACPI_OPERAND_OBJECT
*) context
;
507 /* Parameter validation */
513 /* Convert and validate the device handle */
515 node
= acpi_ns_convert_handle_to_entry (obj_handle
);
517 return (AE_BAD_PARAMETER
);
521 * We only care about regions.and objects
522 * that can have address handlers
525 if ((node
->type
!= ACPI_TYPE_DEVICE
) &&
526 (node
->type
!= ACPI_TYPE_REGION
) &&
527 (node
!= acpi_gbl_root_node
))
532 /* Check for an existing internal object */
534 obj_desc
= acpi_ns_get_attached_object ((ACPI_HANDLE
) node
);
537 * The object DNE, we don't care about it
543 * Devices are handled different than regions
545 if (IS_THIS_OBJECT_TYPE (obj_desc
, ACPI_TYPE_DEVICE
)) {
547 * See if this guy has any handlers
549 tmp_obj
= obj_desc
->device
.addr_handler
;
552 * Now let's see if it's for the same address space.
554 if (tmp_obj
->addr_handler
.space_id
== handler_obj
->addr_handler
.space_id
) {
556 * It's for the same address space
560 * Since the object we found it on was a device, then it
561 * means that someone has already installed a handler for
562 * the branch of the namespace from this device on. Just
563 * bail out telling the walk routine to not traverse this
564 * branch. This preserves the scoping rule for handlers.
566 return (AE_CTRL_DEPTH
);
570 * Move through the linked list of handlers
572 tmp_obj
= tmp_obj
->addr_handler
.next
;
576 * As long as the device didn't have a handler for this
577 * space we don't care about it. We just ignore it and
584 * Only here if it was a region
586 ACPI_ASSERT (obj_desc
->common
.type
== ACPI_TYPE_REGION
);
588 if (obj_desc
->region
.space_id
!= handler_obj
->addr_handler
.space_id
) {
590 * This region is for a different address space
597 * Now we have a region and it is for the handler's address
600 * First disconnect region for any previous handler (if any)
602 acpi_ev_disassociate_region_from_handler (obj_desc
, FALSE
);
605 * Then connect the region to the new handler
607 status
= acpi_ev_associate_region_and_handler (handler_obj
, obj_desc
, FALSE
);