ACPICA: Update for "orphan" embedded controller _REG method support

This refers to _REG methods under the EC device that have no
corresponding operation region. This is allowed by the ACPI
specification. This update removes a dependency on having an
ECDT table, and will execute an orphan _REG method as long as
the handler for the EC is installed at the EC device node (not
the namespace root).  Rui Zhang (original update), Bob Moore
(update/integrate).

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Acked-by: Len Brown <len.brown@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
Zhang Rui 2013-05-30 10:02:13 +08:00 committed by Rafael J. Wysocki
parent d835e7f4f8
commit 8f4f5e7815
1 changed files with 21 additions and 40 deletions

View File

@ -54,7 +54,8 @@ extern u8 acpi_gbl_default_address_spaces[];
/* Local prototypes */ /* Local prototypes */
static void acpi_ev_orphan_ec_reg_method(void); static void
acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node);
static acpi_status static acpi_status
acpi_ev_reg_run(acpi_handle obj_handle, acpi_ev_reg_run(acpi_handle obj_handle,
@ -612,7 +613,7 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
/* Special case for EC: handle "orphan" _REG methods with no region */ /* Special case for EC: handle "orphan" _REG methods with no region */
if (space_id == ACPI_ADR_SPACE_EC) { if (space_id == ACPI_ADR_SPACE_EC) {
acpi_ev_orphan_ec_reg_method(); acpi_ev_orphan_ec_reg_method(node);
} }
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
@ -681,7 +682,7 @@ acpi_ev_reg_run(acpi_handle obj_handle,
* *
* FUNCTION: acpi_ev_orphan_ec_reg_method * FUNCTION: acpi_ev_orphan_ec_reg_method
* *
* PARAMETERS: None * PARAMETERS: ec_device_node - Namespace node for an EC device
* *
* RETURN: None * RETURN: None
* *
@ -693,37 +694,27 @@ acpi_ev_reg_run(acpi_handle obj_handle,
* detected by providing a _REG method object underneath the * detected by providing a _REG method object underneath the
* Embedded Controller device." * Embedded Controller device."
* *
* To quickly access the EC device, we use the EC_ID that appears * To quickly access the EC device, we use the ec_device_node used
* within the ECDT. Otherwise, we would need to perform a time- * during EC handler installation. Otherwise, we would need to
* consuming namespace walk, executing _HID methods to find the * perform a time consuming namespace walk, executing _HID
* EC device. * methods to find the EC device.
*
* MUTEX: Assumes the namespace is locked
* *
******************************************************************************/ ******************************************************************************/
static void acpi_ev_orphan_ec_reg_method(void) static void
acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node)
{ {
struct acpi_table_ecdt *table; acpi_handle reg_method;
struct acpi_namespace_node *next_node;
acpi_status status; acpi_status status;
struct acpi_object_list args; struct acpi_object_list args;
union acpi_object objects[2]; union acpi_object objects[2];
struct acpi_namespace_node *ec_device_node;
struct acpi_namespace_node *reg_method;
struct acpi_namespace_node *next_node;
ACPI_FUNCTION_TRACE(ev_orphan_ec_reg_method); ACPI_FUNCTION_TRACE(ev_orphan_ec_reg_method);
/* Get the ECDT (if present in system) */ if (!ec_device_node) {
status = acpi_get_table(ACPI_SIG_ECDT, 0,
ACPI_CAST_INDIRECT_PTR(struct acpi_table_header,
&table));
if (ACPI_FAILURE(status)) {
return_VOID;
}
/* We need a valid EC_ID string */
if (!(*table->id)) {
return_VOID; return_VOID;
} }
@ -731,22 +722,11 @@ static void acpi_ev_orphan_ec_reg_method(void)
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
/* Get a handle to the EC device referenced in the ECDT */
status = acpi_get_handle(NULL,
ACPI_CAST_PTR(char, table->id),
ACPI_CAST_PTR(acpi_handle, &ec_device_node));
if (ACPI_FAILURE(status)) {
goto exit;
}
/* Get a handle to a _REG method immediately under the EC device */ /* Get a handle to a _REG method immediately under the EC device */
status = acpi_get_handle(ec_device_node, status = acpi_get_handle(ec_device_node, METHOD_NAME__REG, &reg_method);
METHOD_NAME__REG, ACPI_CAST_PTR(acpi_handle,
&reg_method));
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
goto exit; goto exit; /* There is no _REG method present */
} }
/* /*
@ -754,19 +734,20 @@ static void acpi_ev_orphan_ec_reg_method(void)
* this scope with the Embedded Controller space ID. Otherwise, it * this scope with the Embedded Controller space ID. Otherwise, it
* will already have been executed. Note, this allows for Regions * will already have been executed. Note, this allows for Regions
* with other space IDs to be present; but the code below will then * with other space IDs to be present; but the code below will then
* execute the _REG method with the EC space ID argument. * execute the _REG method with the embedded_control space_ID argument.
*/ */
next_node = acpi_ns_get_next_node(ec_device_node, NULL); next_node = acpi_ns_get_next_node(ec_device_node, NULL);
while (next_node) { while (next_node) {
if ((next_node->type == ACPI_TYPE_REGION) && if ((next_node->type == ACPI_TYPE_REGION) &&
(next_node->object) && (next_node->object) &&
(next_node->object->region.space_id == ACPI_ADR_SPACE_EC)) { (next_node->object->region.space_id == ACPI_ADR_SPACE_EC)) {
goto exit; /* Do not execute _REG */ goto exit; /* Do not execute the _REG */
} }
next_node = acpi_ns_get_next_node(ec_device_node, next_node); next_node = acpi_ns_get_next_node(ec_device_node, next_node);
} }
/* Evaluate the _REG(EC,Connect) method */ /* Evaluate the _REG(embedded_control,Connect) method */
args.count = 2; args.count = 2;
args.pointer = objects; args.pointer = objects;