aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLin Ming <ming.m.lin@intel.com>2009-05-20 22:42:09 -0400
committerLen Brown <len.brown@intel.com>2009-05-27 00:35:51 -0400
commitb2f7ddcfcb9c2436896cb339a7ff70245648f033 (patch)
treeefd130b46b0dff8855e11d63612532dc60d635dc
parente0be6f5a9863b626c19f0be04946c6285cc9db56 (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.h1
-rw-r--r--drivers/acpi/acpica/amlcode.h2
-rw-r--r--drivers/acpi/acpica/excreate.c2
-rw-r--r--drivers/acpi/acpica/exdump.c6
-rw-r--r--drivers/acpi/acpica/nsobject.c9
-rw-r--r--drivers/acpi/acpica/nsxfname.c150
-rw-r--r--include/acpi/acpixf.h2
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
123static struct acpi_exdump_info acpi_ex_dump_method[8] = { 123static 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
50ACPI_MODULE_NAME("nsxfname") 52ACPI_MODULE_NAME("nsxfname")
@@ -358,3 +360,151 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
358} 360}
359 361
360ACPI_EXPORT_SYMBOL(acpi_get_object_info) 362ACPI_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 ******************************************************************************/
378acpi_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
504error_exit:
505
506 ACPI_FREE(aml_buffer);
507 ACPI_FREE(method_obj);
508 return status;
509}
510ACPI_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,
201acpi_status 201acpi_status
202acpi_get_object_info(acpi_handle handle, struct acpi_buffer *return_buffer); 202acpi_get_object_info(acpi_handle handle, struct acpi_buffer *return_buffer);
203 203
204acpi_status acpi_install_method(u8 *buffer);
205
204acpi_status 206acpi_status
205acpi_get_next_object(acpi_object_type type, 207acpi_get_next_object(acpi_object_type type,
206 acpi_handle parent, 208 acpi_handle parent,