static acpi_status acpi_ev_install_handler(acpi_handle obj_handle, u32 level, void *context, void **return_value) { union acpi_operand_object *handler_obj; union acpi_operand_object *next_handler_obj; union acpi_operand_object *obj_desc; struct acpi_namespace_node *node; acpi_status status; ACPI_FUNCTION_NAME(ev_install_handler); handler_obj = (union acpi_operand_object *)context; /* Parameter validation */ if (!handler_obj) { return (AE_OK); } /* Convert and validate the device handle */ node = acpi_ns_map_handle_to_node(obj_handle); if (!node) { return (AE_BAD_PARAMETER); } /* * We only care about regions.and objects * that are allowed to have address space handlers */ if ((node->type != ACPI_TYPE_DEVICE) && (node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) { return (AE_OK); } /* Check for an existing internal object */ obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { /* No object, just exit */ return (AE_OK); } /* Devices are handled different than regions */ if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_DEVICE) { /* Check if this Device already has a handler for this address space */ next_handler_obj = obj_desc->device.handler; while (next_handler_obj) { /* Found a handler, is it for the same address space? */ if (next_handler_obj->address_space.space_id == handler_obj->address_space.space_id) { ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Found handler for region [%s] in device %p(%p) handler %p\n", acpi_ut_get_region_name (handler_obj->address_space. space_id), obj_desc, next_handler_obj, handler_obj)); /* * Since the object we found it on was a device, then it * means that someone has already installed a handler for * the branch of the namespace from this device on. Just * bail out telling the walk routine to not traverse this * branch. This preserves the scoping rule for handlers. */ return (AE_CTRL_DEPTH); } /* Walk the linked list of handlers attached to this device */ next_handler_obj = next_handler_obj->address_space.next; } /* * As long as the device didn't have a handler for this * space we don't care about it. We just ignore it and * proceed. */ return (AE_OK); } /* Object is a Region */ if (obj_desc->region.space_id != handler_obj->address_space.space_id) { /* * This region is for a different address space * -- just ignore it */ return (AE_OK); } /* * Now we have a region and it is for the handler's address * space type. * * First disconnect region for any previous handler (if any) */ acpi_ev_detach_region(obj_desc, FALSE); /* Connect the region to the new handler */ status = acpi_ev_attach_region(handler_obj, obj_desc, FALSE); return (status); }
acpi_status acpi_ev_initialize_region(union acpi_operand_object *region_obj, u8 acpi_ns_locked) { union acpi_operand_object *handler_obj; union acpi_operand_object *obj_desc; acpi_adr_space_type space_id; struct acpi_namespace_node *node; acpi_status status; struct acpi_namespace_node *method_node; acpi_name *reg_name_ptr = (acpi_name *) METHOD_NAME__REG; union acpi_operand_object *region_obj2; ACPI_FUNCTION_TRACE_U32(ev_initialize_region, acpi_ns_locked); if (!region_obj) { return_ACPI_STATUS(AE_BAD_PARAMETER); } if (region_obj->common.flags & AOPOBJ_OBJECT_INITIALIZED) { return_ACPI_STATUS(AE_OK); } region_obj2 = acpi_ns_get_secondary_object(region_obj); if (!region_obj2) { return_ACPI_STATUS(AE_NOT_EXIST); } node = acpi_ns_get_parent_node(region_obj->region.node); space_id = region_obj->region.space_id; /* Setup defaults */ region_obj->region.handler = NULL; region_obj2->extra.method_REG = NULL; region_obj->common.flags &= ~(AOPOBJ_SETUP_COMPLETE); region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED; /* Find any "_REG" method associated with this region definition */ status = acpi_ns_search_one_scope(*reg_name_ptr, node, ACPI_TYPE_METHOD, &method_node); if (ACPI_SUCCESS(status)) { /* * The _REG method is optional and there can be only one per region * definition. This will be executed when the handler is attached * or removed */ region_obj2->extra.method_REG = method_node; } /* * The following loop depends upon the root Node having no parent * ie: acpi_gbl_root_node->parent_entry being set to NULL */ while (node) { /* Check to see if a handler exists */ handler_obj = NULL; obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { /* Can only be a handler if the object exists */ switch (node->type) { case ACPI_TYPE_DEVICE: handler_obj = obj_desc->device.handler; break; case ACPI_TYPE_PROCESSOR: handler_obj = obj_desc->processor.handler; break; case ACPI_TYPE_THERMAL: handler_obj = obj_desc->thermal_zone.handler; break; default: /* Ignore other objects */ break; } while (handler_obj) { /* Is this handler of the correct type? */ if (handler_obj->address_space.space_id == space_id) { /* Found correct handler */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Found handler %p for region %p in obj %p\n", handler_obj, region_obj, obj_desc)); status = acpi_ev_attach_region(handler_obj, region_obj, acpi_ns_locked); /* * Tell all users that this region is usable by running the _REG * method */ if (acpi_ns_locked) { status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS (status); } } status = acpi_ev_execute_reg_method (region_obj, 1); if (acpi_ns_locked) { status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS (status); } } return_ACPI_STATUS(AE_OK); } /* Try next handler in the list */ handler_obj = handler_obj->address_space.next; } } /* * This node does not have the handler we need; * Pop up one level */ node = acpi_ns_get_parent_node(node); } /* If we get here, there is no handler for this region */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "No handler for RegionType %s(%X) (RegionObj %p)\n", acpi_ut_get_region_name(space_id), space_id, region_obj)); return_ACPI_STATUS(AE_NOT_EXIST); }
acpi_status acpi_ev_initialize_region(union acpi_operand_object *region_obj, u8 acpi_ns_locked) { union acpi_operand_object *handler_obj; union acpi_operand_object *obj_desc; acpi_adr_space_type space_id; struct acpi_namespace_node *node; acpi_status status; ACPI_FUNCTION_TRACE_U32(ev_initialize_region, acpi_ns_locked); if (!region_obj) { return_ACPI_STATUS(AE_BAD_PARAMETER); } if (region_obj->common.flags & AOPOBJ_OBJECT_INITIALIZED) { return_ACPI_STATUS(AE_OK); } acpi_ev_associate_reg_method(region_obj); region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED; node = region_obj->region.node->parent; space_id = region_obj->region.space_id; /* * The following loop depends upon the root Node having no parent * ie: acpi_gbl_root_node->Parent being set to NULL */ while (node) { /* Check to see if a handler exists */ handler_obj = NULL; obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { /* Can only be a handler if the object exists */ switch (node->type) { case ACPI_TYPE_DEVICE: case ACPI_TYPE_PROCESSOR: case ACPI_TYPE_THERMAL: handler_obj = obj_desc->common_notify.handler; break; case ACPI_TYPE_METHOD: /* * If we are executing module level code, the original * Node's object was replaced by this Method object and we * saved the handler in the method object. * * See acpi_ns_exec_module_code */ if (obj_desc->method. info_flags & ACPI_METHOD_MODULE_LEVEL) { handler_obj = obj_desc->method.dispatch.handler; } break; default: /* Ignore other objects */ break; } handler_obj = acpi_ev_find_region_handler(space_id, handler_obj); if (handler_obj) { /* Found correct handler */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Found handler %p for region %p in obj %p\n", handler_obj, region_obj, obj_desc)); status = acpi_ev_attach_region(handler_obj, region_obj, acpi_ns_locked); /* * Tell all users that this region is usable by * running the _REG method */ if (acpi_ns_locked) { status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } status = acpi_ev_execute_reg_method(region_obj, ACPI_REG_CONNECT); if (acpi_ns_locked) { status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } return_ACPI_STATUS(AE_OK); } } /* This node does not have the handler we need; Pop up one level */ node = node->parent; } /* If we get here, there is no handler for this region */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "No handler for RegionType %s(%X) (RegionObj %p)\n", acpi_ut_get_region_name(space_id), space_id, region_obj)); return_ACPI_STATUS(AE_NOT_EXIST); }