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/acpi/acpica/nsxfname.c | |
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/acpi/acpica/nsxfname.c')
-rw-r--r-- | drivers/acpi/acpica/nsxfname.c | 150 |
1 files changed, 150 insertions, 0 deletions
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) | ||