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 /drivers | |
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>
Diffstat (limited to 'drivers')
-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 |
6 files changed, 166 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) | ||