📄 evregion.c
字号:
*/ region_obj->region.handler = NULL; acpi_ut_remove_reference (handler_obj); return_VOID; } /* Walk the linked list of handlers */ last_obj_ptr = &obj_desc->region.next; obj_desc = obj_desc->region.next; } /* If we get here, the region was not in the handler's region list */ ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, "Cannot remove region %p from address handler %p\n", region_obj, handler_obj)); return_VOID;}/******************************************************************************* * * FUNCTION: acpi_ev_attach_region * * PARAMETERS: handler_obj - Handler Object * region_obj - Region Object * acpi_ns_is_locked - Namespace Region Already Locked? * * RETURN: None * * DESCRIPTION: Create the association between the handler and the region * this is a two way association. * ******************************************************************************/acpi_statusacpi_ev_attach_region ( union acpi_operand_object *handler_obj, union acpi_operand_object *region_obj, u8 acpi_ns_is_locked){ ACPI_FUNCTION_TRACE ("ev_attach_region"); ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, "Adding Region [%4.4s] %p to address handler %p [%s]\n", acpi_ut_get_node_name (region_obj->region.node), region_obj, handler_obj, acpi_ut_get_region_name (region_obj->region.space_id))); /* Link this region to the front of the handler's list */ region_obj->region.next = handler_obj->address_space.region_list; handler_obj->address_space.region_list = region_obj; /* Install the region's handler */ if (region_obj->region.handler) { return_ACPI_STATUS (AE_ALREADY_EXISTS); } region_obj->region.handler = handler_obj; acpi_ut_add_reference (handler_obj); return_ACPI_STATUS (AE_OK);}/******************************************************************************* * * FUNCTION: acpi_ev_install_handler * * PARAMETERS: walk_namespace callback * * DESCRIPTION: This routine installs an address handler into objects that are * of type Region or Device. * * If the Object is a Device, and the device has a handler of * the same type then the search is terminated in that branch. * * This is because the existing handler is closer in proximity * to any more regions than the one we are trying to install. * ******************************************************************************/acpi_statusacpi_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);}/******************************************************************************* * * FUNCTION: acpi_ev_install_space_handler * * PARAMETERS: Node - Namespace node for the device * space_id - The address space ID * Handler - Address of the handler * Setup - Address of the setup function * Context - Value passed to the handler on each access * * RETURN: Status * * DESCRIPTION: Install a handler for all op_regions of a given space_id. * Assumes namespace is locked * ******************************************************************************/acpi_statusacpi_ev_install_space_handler ( struct acpi_namespace_node *node, acpi_adr_space_type space_id, acpi_adr_space_handler handler, acpi_adr_space_setup setup, void *context){ union acpi_operand_object *obj_desc; union acpi_operand_object *handler_obj; acpi_status status; acpi_object_type type; u16 flags = 0; ACPI_FUNCTION_TRACE ("ev_install_space_handler"); /* * This registration is valid for only the types below * and the root. This is where the default handlers * get placed. */ if ((node->type != ACPI_TYPE_DEVICE) && (node->type != ACPI_TYPE_PROCESSOR) && (node->type != ACPI_TYPE_THERMAL) && (node != acpi_gbl_root_node)) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } if (handler == ACPI_DEFAULT_HANDLER) { flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED; switch (space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: handler = acpi_ex_system_memory_space_handler; setup = acpi_ev_system_memory_region_setup; break; case ACPI_ADR_SPACE_SYSTEM_IO: handler = acpi_ex_system_io_space_handler; setup = acpi_ev_io_space_region_setup; break; case ACPI_ADR_SPACE_PCI_CONFIG: handler = acpi_ex_pci_config_space_handler; setup = acpi_ev_pci_config_region_setup; break; case ACPI_ADR_SPACE_CMOS: handler = acpi_ex_cmos_space_handler; setup = acpi_ev_cmos_region_setup; break; case ACPI_ADR_SPACE_PCI_BAR_TARGET: handler = acpi_ex_pci_bar_space_handler; setup = acpi_ev_pci_bar_region_setup; break; case ACPI_ADR_SPACE_DATA_TABLE: handler = acpi_ex_data_table_space_handler; setup = NULL; break; default: status = AE_BAD_PARAMETER; goto unlock_and_exit; } } /* If the caller hasn't specified a setup routine, use the default */ if (!setup) { setup = acpi_ev_default_region_setup; } /* Check for an existing internal object */ obj_desc = acpi_ns_get_attached_object (node); if (obj_desc) { /* * The attached device object already exists. * Make sure the handler is not already installed. */ handler_obj = obj_desc->device.handler; /* Walk the handler list for this device */ while (handler_obj) { /* Same space_id indicates a handler already installed */ if (handler_obj->address_space.space_id == space_id) { if (handler_obj->address_space.handler == handler) { /* * It is (relatively) OK to attempt to install the SAME * handler twice. This can easily happen with PCI_Config space. */ status = AE_SAME_HANDLER; goto unlock_and_exit; } else { /* A handler is already installed */ status = AE_ALREADY_EXISTS; } goto unlock_and_exit; } /* Walk the linked list of handlers */ handler_obj = handler_obj->address_space.next; } } else { ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, "Creating object on Device %p while installing handler\n", node)); /* obj_desc does not exist, create one */ if (node->type == ACPI_TYPE_ANY) { type = ACPI_TYPE_DEVICE; } else { type = node->type; } obj_desc = acpi_ut_create_internal_object (type); if (!obj_desc) { status = AE_NO_MEMORY; goto unlock_and_exit; } /* Init new descriptor */ obj_desc->common.type = (u8) type; /* Attach the new object to the Node */ status = acpi_ns_attach_object (node, obj_desc, type); /* Remove local reference to the object */ acpi_ut_remove_reference (obj_desc); if (ACPI_FAILURE (status)) { goto unlock_and_exit; } } ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n", acpi_ut_get_region_name (space_id), space_id, acpi_ut_get_node_name (node), node, obj_desc)); /* * Install the handler * * At this point there is no existing handler. * Just allocate the object for the handler and link it * into the list. */ handler_obj = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_ADDRESS_HANDLER); if (!handler_obj) { status = AE_NO_MEMORY; goto unlock_and_exit; } /* Init handler obj */ handler_obj->address_space.space_id = (u8) space_id; handler_obj->address_space.hflags = flags; handler_obj->address_space.region_list = NULL; handler_obj->address_space.node = node; handler_obj->address_space.handler = handler; handler_obj->address_space.context = context; handler_obj->address_space.setup = setup; /* Install at head of Device.address_space list */ handler_obj->address_space.next = obj_desc->device.handler; /* * The Device object is the first reference on the handler_obj. * Each region that uses the handler adds a reference. */ obj_desc->device.handler = handler_obj; /* * Walk the namespace finding all of the regions this * handler will manage. * * Start at the device and search the branch toward * the leaf nodes until either the leaf is encountered or * a device is detected that has an address handler of the * same type. * * In either case, back up and search down the remainder * of the branch */ status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_install_handler, handler_obj, NULL);unlock_and_exit: return_ACPI_STATUS (status);}/******************************************************************************* * * FUNCTION: acpi_ev_execute_reg_methods * * PARAMETERS: Node - Namespace node for the device * space_id - The address space ID * * RETURN: Status * * DESCRIPTION: Run all _REG methods for the input Space ID; * Note: assumes namespace is locked, or system init time. * ******************************************************************************/acpi_statusacpi_ev_execute_reg_methods ( struct acpi_namespace_node *node, acpi_adr_space_type space_id){ acpi_status status; ACPI_FUNCTION_TRACE ("ev_execute_reg_methods"); /* * Run all _REG methods for all Operation Regions for this * space ID. This is a separate walk in order to handle any * interdependencies between regions and _REG methods. (i.e. handlers * must be installed for all regions of this Space ID before we * can run any _REG methods) */ status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, &space_id, NULL); return_ACPI_STATUS (status);}/******************************************************************************* * * FUNCTION: acpi_ev_reg_run * * PARAMETERS: walk_namespace callback * * DESCRIPTION: Run _REg method for region objects of the requested space_iD * ******************************************************************************/acpi_statusacpi_ev_reg_run ( acpi_handle obj_handle, u32 level, void *context, void **return_value){ union acpi_operand_object *obj_desc; struct acpi_namespace_node *node; acpi_adr_space_type space_id; acpi_status status; space_id = *ACPI_CAST_PTR (acpi_adr_space_type, context); /* 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_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); } /* Object is a Region */ if (obj_desc->region.space_id != space_id) { /* * This region is for a different address space * -- just ignore it */ return (AE_OK); } status = acpi_ev_execute_reg_method (obj_desc, 1); return (status);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -