diff options
| author | Lin Ming <ming.m.lin@intel.com> | 2009-05-20 22:42:09 -0400 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2009-05-27 00:35:51 -0400 |
| commit | b2f7ddcfcb9c2436896cb339a7ff70245648f033 (patch) | |
| tree | efd130b46b0dff8855e11d63612532dc60d635dc | |
| parent | e0be6f5a9863b626c19f0be04946c6285cc9db56 (diff) | |
ACPICA: New: AcpiInstallMethod - install a single control method
This interface enables the override or creation of a single
control method. Useful to repair a bug or install a missing method.
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
| -rw-r--r-- | drivers/acpi/acpica/aclocal.h | 1 | ||||
| -rw-r--r-- | drivers/acpi/acpica/amlcode.h | 2 | ||||
| -rw-r--r-- | drivers/acpi/acpica/excreate.c | 2 | ||||
| -rw-r--r-- | drivers/acpi/acpica/exdump.c | 6 | ||||
| -rw-r--r-- | drivers/acpi/acpica/nsobject.c | 9 | ||||
| -rw-r--r-- | drivers/acpi/acpica/nsxfname.c | 150 | ||||
| -rw-r--r-- | include/acpi/acpixf.h | 2 |
7 files changed, 168 insertions, 4 deletions
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 2ec394a328e9..882b4b55867f 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h | |||
| @@ -205,6 +205,7 @@ struct acpi_namespace_node { | |||
| 205 | #define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ | 205 | #define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ |
| 206 | #define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ | 206 | #define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ |
| 207 | #define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */ | 207 | #define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */ |
| 208 | #define ANOBJ_ALLOCATED_BUFFER 0x40 /* Method AML buffer is dynamic (install_method) */ | ||
| 208 | 209 | ||
| 209 | #define ANOBJ_IS_EXTERNAL 0x08 /* i_aSL only: This object created via External() */ | 210 | #define ANOBJ_IS_EXTERNAL 0x08 /* i_aSL only: This object created via External() */ |
| 210 | #define ANOBJ_METHOD_NO_RETVAL 0x10 /* i_aSL only: Method has no return value */ | 211 | #define ANOBJ_METHOD_NO_RETVAL 0x10 /* i_aSL only: Method has no return value */ |
diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index ff851c5df698..067f967eb389 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h | |||
| @@ -483,7 +483,7 @@ typedef enum { | |||
| 483 | 483 | ||
| 484 | #define AML_METHOD_ARG_COUNT 0x07 | 484 | #define AML_METHOD_ARG_COUNT 0x07 |
| 485 | #define AML_METHOD_SERIALIZED 0x08 | 485 | #define AML_METHOD_SERIALIZED 0x08 |
| 486 | #define AML_METHOD_SYNCH_LEVEL 0xF0 | 486 | #define AML_METHOD_SYNC_LEVEL 0xF0 |
| 487 | 487 | ||
| 488 | /* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */ | 488 | /* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */ |
| 489 | 489 | ||
diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index a57ad2564ab0..02b25d233d99 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c | |||
| @@ -502,7 +502,7 @@ acpi_ex_create_method(u8 * aml_start, | |||
| 502 | * ACPI 2.0: sync_level = sync_level in method declaration | 502 | * ACPI 2.0: sync_level = sync_level in method declaration |
| 503 | */ | 503 | */ |
| 504 | obj_desc->method.sync_level = (u8) | 504 | obj_desc->method.sync_level = (u8) |
| 505 | ((method_flags & AML_METHOD_SYNCH_LEVEL) >> 4); | 505 | ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); |
| 506 | } | 506 | } |
| 507 | 507 | ||
| 508 | /* Attach the new object to the method Node */ | 508 | /* Attach the new object to the method Node */ |
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 89d141fdae0b..ec524614e708 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c | |||
| @@ -120,9 +120,11 @@ static struct acpi_exdump_info acpi_ex_dump_event[2] = { | |||
| 120 | {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(event.os_semaphore), "OsSemaphore"} | 120 | {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(event.os_semaphore), "OsSemaphore"} |
| 121 | }; | 121 | }; |
| 122 | 122 | ||
| 123 | static struct acpi_exdump_info acpi_ex_dump_method[8] = { | 123 | static struct acpi_exdump_info acpi_ex_dump_method[9] = { |
| 124 | {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_method), NULL}, | 124 | {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_method), NULL}, |
| 125 | {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), "ParamCount"}, | 125 | {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.method_flags), "Method Flags"}, |
| 126 | {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), | ||
| 127 | "Parameter Count"}, | ||
| 126 | {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.sync_level), "Sync Level"}, | 128 | {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.sync_level), "Sync Level"}, |
| 127 | {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.mutex), "Mutex"}, | 129 | {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.mutex), "Mutex"}, |
| 128 | {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.owner_id), "Owner Id"}, | 130 | {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.owner_id), "Owner Id"}, |
diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c index 3eb20bfda9d8..60f3af08d28c 100644 --- a/drivers/acpi/acpica/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c | |||
| @@ -213,6 +213,15 @@ void acpi_ns_detach_object(struct acpi_namespace_node *node) | |||
| 213 | return_VOID; | 213 | return_VOID; |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | if (node->flags & ANOBJ_ALLOCATED_BUFFER) { | ||
| 217 | |||
| 218 | /* Free the dynamic aml buffer */ | ||
| 219 | |||
| 220 | if (obj_desc->common.type == ACPI_TYPE_METHOD) { | ||
| 221 | ACPI_FREE(obj_desc->method.aml_start); | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 216 | /* Clear the entry in all cases */ | 225 | /* Clear the entry in all cases */ |
| 217 | 226 | ||
| 218 | node->object = NULL; | 227 | node->object = NULL; |
diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 9589fea24997..f23593d6add4 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c | |||
| @@ -45,6 +45,8 @@ | |||
| 45 | #include <acpi/acpi.h> | 45 | #include <acpi/acpi.h> |
| 46 | #include "accommon.h" | 46 | #include "accommon.h" |
| 47 | #include "acnamesp.h" | 47 | #include "acnamesp.h" |
| 48 | #include "acparser.h" | ||
| 49 | #include "amlcode.h" | ||
| 48 | 50 | ||
| 49 | #define _COMPONENT ACPI_NAMESPACE | 51 | #define _COMPONENT ACPI_NAMESPACE |
| 50 | ACPI_MODULE_NAME("nsxfname") | 52 | ACPI_MODULE_NAME("nsxfname") |
| @@ -358,3 +360,151 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer) | |||
| 358 | } | 360 | } |
| 359 | 361 | ||
| 360 | ACPI_EXPORT_SYMBOL(acpi_get_object_info) | 362 | ACPI_EXPORT_SYMBOL(acpi_get_object_info) |
| 363 | |||
| 364 | /****************************************************************************** | ||
| 365 | * | ||
| 366 | * FUNCTION: acpi_install_method | ||
| 367 | * | ||
| 368 | * PARAMETERS: Buffer - An ACPI table containing one control method | ||
| 369 | * | ||
| 370 | * RETURN: Status | ||
| 371 | * | ||
| 372 | * DESCRIPTION: Install a control method into the namespace. If the method | ||
| 373 | * name already exists in the namespace, it is overwritten. The | ||
| 374 | * input buffer must contain a valid DSDT or SSDT containing a | ||
| 375 | * single control method. | ||
| 376 | * | ||
| 377 | ******************************************************************************/ | ||
| 378 | acpi_status acpi_install_method(u8 *buffer) | ||
| 379 | { | ||
| 380 | struct acpi_table_header *table = | ||
| 381 | ACPI_CAST_PTR(struct acpi_table_header, buffer); | ||
| 382 | u8 *aml_buffer; | ||
| 383 | u8 *aml_start; | ||
| 384 | char *path; | ||
| 385 | struct acpi_namespace_node *node; | ||
| 386 | union acpi_operand_object *method_obj; | ||
| 387 | struct acpi_parse_state parser_state; | ||
| 388 | u32 aml_length; | ||
| 389 | u16 opcode; | ||
| 390 | u8 method_flags; | ||
| 391 | acpi_status status; | ||
| 392 | |||
| 393 | /* Parameter validation */ | ||
| 394 | |||
| 395 | if (!buffer) { | ||
| 396 | return AE_BAD_PARAMETER; | ||
| 397 | } | ||
| 398 | |||
| 399 | /* Table must be a DSDT or SSDT */ | ||
| 400 | |||
| 401 | if (!ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) && | ||
| 402 | !ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) { | ||
| 403 | return AE_BAD_HEADER; | ||
| 404 | } | ||
| 405 | |||
| 406 | /* First AML opcode in the table must be a control method */ | ||
| 407 | |||
| 408 | parser_state.aml = buffer + sizeof(struct acpi_table_header); | ||
| 409 | opcode = acpi_ps_peek_opcode(&parser_state); | ||
| 410 | if (opcode != AML_METHOD_OP) { | ||
| 411 | return AE_BAD_PARAMETER; | ||
| 412 | } | ||
| 413 | |||
| 414 | /* Extract method information from the raw AML */ | ||
| 415 | |||
| 416 | parser_state.aml += acpi_ps_get_opcode_size(opcode); | ||
| 417 | parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state); | ||
| 418 | path = acpi_ps_get_next_namestring(&parser_state); | ||
| 419 | method_flags = *parser_state.aml++; | ||
| 420 | aml_start = parser_state.aml; | ||
| 421 | aml_length = ACPI_PTR_DIFF(parser_state.pkg_end, aml_start); | ||
| 422 | |||
| 423 | /* | ||
| 424 | * Allocate resources up-front. We don't want to have to delete a new | ||
| 425 | * node from the namespace if we cannot allocate memory. | ||
| 426 | */ | ||
| 427 | aml_buffer = ACPI_ALLOCATE(aml_length); | ||
| 428 | if (!aml_buffer) { | ||
| 429 | return AE_NO_MEMORY; | ||
| 430 | } | ||
| 431 | |||
| 432 | method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); | ||
| 433 | if (!method_obj) { | ||
| 434 | ACPI_FREE(aml_buffer); | ||
| 435 | return AE_NO_MEMORY; | ||
| 436 | } | ||
| 437 | |||
| 438 | /* Lock namespace for acpi_ns_lookup, we may be creating a new node */ | ||
| 439 | |||
| 440 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); | ||
| 441 | if (ACPI_FAILURE(status)) { | ||
| 442 | goto error_exit; | ||
| 443 | } | ||
| 444 | |||
| 445 | /* The lookup either returns an existing node or creates a new one */ | ||
| 446 | |||
| 447 | status = | ||
| 448 | acpi_ns_lookup(NULL, path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1, | ||
| 449 | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND, | ||
| 450 | NULL, &node); | ||
| 451 | |||
| 452 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | ||
| 453 | |||
| 454 | if (ACPI_FAILURE(status)) { /* ns_lookup */ | ||
| 455 | if (status != AE_ALREADY_EXISTS) { | ||
| 456 | goto error_exit; | ||
| 457 | } | ||
| 458 | |||
| 459 | /* Node existed previously, make sure it is a method node */ | ||
| 460 | |||
| 461 | if (node->type != ACPI_TYPE_METHOD) { | ||
| 462 | status = AE_TYPE; | ||
| 463 | goto error_exit; | ||
| 464 | } | ||
| 465 | } | ||
| 466 | |||
| 467 | /* Copy the method AML to the local buffer */ | ||
| 468 | |||
| 469 | ACPI_MEMCPY(aml_buffer, aml_start, aml_length); | ||
| 470 | |||
| 471 | /* Initialize the method object with the new method's information */ | ||
| 472 | |||
| 473 | method_obj->method.aml_start = aml_buffer; | ||
| 474 | method_obj->method.aml_length = aml_length; | ||
| 475 | |||
| 476 | method_obj->method.param_count = (u8) | ||
| 477 | (method_flags & AML_METHOD_ARG_COUNT); | ||
| 478 | |||
| 479 | method_obj->method.method_flags = (u8) | ||
| 480 | (method_flags & ~AML_METHOD_ARG_COUNT); | ||
| 481 | |||
| 482 | if (method_flags & AML_METHOD_SERIALIZED) { | ||
| 483 | method_obj->method.sync_level = (u8) | ||
| 484 | ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); | ||
| 485 | } | ||
| 486 | |||
| 487 | /* | ||
| 488 | * Now that it is complete, we can attach the new method object to | ||
| 489 | * the method Node (detaches/deletes any existing object) | ||
| 490 | */ | ||
| 491 | status = acpi_ns_attach_object(node, method_obj, ACPI_TYPE_METHOD); | ||
| 492 | |||
| 493 | /* | ||
| 494 | * Flag indicates AML buffer is dynamic, must be deleted later. | ||
| 495 | * Must be set only after attach above. | ||
| 496 | */ | ||
| 497 | node->flags |= ANOBJ_ALLOCATED_BUFFER; | ||
| 498 | |||
| 499 | /* Remove local reference to the method object */ | ||
| 500 | |||
| 501 | acpi_ut_remove_reference(method_obj); | ||
| 502 | return status; | ||
| 503 | |||
| 504 | error_exit: | ||
| 505 | |||
| 506 | ACPI_FREE(aml_buffer); | ||
| 507 | ACPI_FREE(method_obj); | ||
| 508 | return status; | ||
| 509 | } | ||
| 510 | ACPI_EXPORT_SYMBOL(acpi_install_method) | ||
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 60b76a3fb3a1..c3b08d3330e3 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h | |||
| @@ -201,6 +201,8 @@ acpi_evaluate_object_typed(acpi_handle object, | |||
| 201 | acpi_status | 201 | acpi_status |
| 202 | acpi_get_object_info(acpi_handle handle, struct acpi_buffer *return_buffer); | 202 | acpi_get_object_info(acpi_handle handle, struct acpi_buffer *return_buffer); |
| 203 | 203 | ||
| 204 | acpi_status acpi_install_method(u8 *buffer); | ||
| 205 | |||
| 204 | acpi_status | 206 | acpi_status |
| 205 | acpi_get_next_object(acpi_object_type type, | 207 | acpi_get_next_object(acpi_object_type type, |
| 206 | acpi_handle parent, | 208 | acpi_handle parent, |
