diff options
author | Alexey Starikovskiy <astarikovskiy@suse.de> | 2007-08-03 17:52:48 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2007-08-03 17:52:48 -0400 |
commit | cd8c93a4e04dce8f00d1ef3a476aac8bd65ae40b (patch) | |
tree | 46872a60d90b61752cc1b4f1533e00ba648eed7d | |
parent | f1cd1fe61b96e4312312d42c0a9784dfab12e007 (diff) |
ACPI: EC: If ECDT is not found, look up EC in DSDT.
Some ASUS laptops access EC space from device _INI methods, but do not
provide ECDT for early EC setup. In order to make them function properly,
there is a need to find EC is DSDT before any _INI is called.
Similar functionality was turned on by acpi_fake_ecdt=1 command line
before. Now it is on all the time.
http://bugzilla.kernel.org/show_bug.cgi?id=8598
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r-- | drivers/acpi/ec.c | 50 |
1 files changed, 28 insertions, 22 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index dd384ec757dd..4d7fe829a6e2 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -664,30 +664,32 @@ acpi_ec_register_query_methods(acpi_handle handle, u32 level, | |||
664 | return AE_OK; | 664 | return AE_OK; |
665 | } | 665 | } |
666 | 666 | ||
667 | static int ec_parse_device(struct acpi_ec *ec, acpi_handle handle) | 667 | static acpi_status |
668 | ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) | ||
668 | { | 669 | { |
669 | if (ACPI_FAILURE(acpi_walk_resources(handle, METHOD_NAME__CRS, | 670 | acpi_status status; |
670 | ec_parse_io_ports, ec))) | 671 | |
671 | return -EINVAL; | 672 | struct acpi_ec *ec = context; |
673 | status = acpi_walk_resources(handle, METHOD_NAME__CRS, | ||
674 | ec_parse_io_ports, ec); | ||
675 | if (ACPI_FAILURE(status)) | ||
676 | return status; | ||
672 | 677 | ||
673 | /* Get GPE bit assignment (EC events). */ | 678 | /* Get GPE bit assignment (EC events). */ |
674 | /* TODO: Add support for _GPE returning a package */ | 679 | /* TODO: Add support for _GPE returning a package */ |
675 | if (ACPI_FAILURE(acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe))) | 680 | status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe); |
676 | return -EINVAL; | 681 | if (ACPI_FAILURE(status)) |
682 | return status; | ||
677 | 683 | ||
678 | /* Use the global lock for all EC transactions? */ | 684 | /* Use the global lock for all EC transactions? */ |
679 | acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); | 685 | acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); |
680 | 686 | ||
681 | /* Find and register all query methods */ | ||
682 | acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1, | ||
683 | acpi_ec_register_query_methods, ec, NULL); | ||
684 | |||
685 | ec->handle = handle; | 687 | ec->handle = handle; |
686 | 688 | ||
687 | printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx", | 689 | printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx", |
688 | ec->gpe, ec->command_addr, ec->data_addr); | 690 | ec->gpe, ec->command_addr, ec->data_addr); |
689 | 691 | ||
690 | return 0; | 692 | return AE_CTRL_TERMINATE; |
691 | } | 693 | } |
692 | 694 | ||
693 | static int acpi_ec_add(struct acpi_device *device) | 695 | static int acpi_ec_add(struct acpi_device *device) |
@@ -704,7 +706,8 @@ static int acpi_ec_add(struct acpi_device *device) | |||
704 | if (!ec) | 706 | if (!ec) |
705 | return -ENOMEM; | 707 | return -ENOMEM; |
706 | 708 | ||
707 | if (ec_parse_device(ec, device->handle)) { | 709 | if (ec_parse_device(device->handle, 0, ec, NULL) != |
710 | AE_CTRL_TERMINATE) { | ||
708 | kfree(ec); | 711 | kfree(ec); |
709 | return -EINVAL; | 712 | return -EINVAL; |
710 | } | 713 | } |
@@ -867,18 +870,21 @@ int __init acpi_ec_ecdt_probe(void) | |||
867 | /* | 870 | /* |
868 | * Generate a boot ec context | 871 | * Generate a boot ec context |
869 | */ | 872 | */ |
870 | |||
871 | status = acpi_get_table(ACPI_SIG_ECDT, 1, | 873 | status = acpi_get_table(ACPI_SIG_ECDT, 1, |
872 | (struct acpi_table_header **)&ecdt_ptr); | 874 | (struct acpi_table_header **)&ecdt_ptr); |
873 | if (ACPI_FAILURE(status)) | 875 | if (ACPI_SUCCESS(status)) { |
874 | goto error; | 876 | printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n\n"); |
875 | 877 | boot_ec->command_addr = ecdt_ptr->control.address; | |
876 | printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n"); | 878 | boot_ec->data_addr = ecdt_ptr->data.address; |
877 | 879 | boot_ec->gpe = ecdt_ptr->gpe; | |
878 | boot_ec->command_addr = ecdt_ptr->control.address; | 880 | boot_ec->handle = ACPI_ROOT_OBJECT; |
879 | boot_ec->data_addr = ecdt_ptr->data.address; | 881 | } else { |
880 | boot_ec->gpe = ecdt_ptr->gpe; | 882 | printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n"); |
881 | boot_ec->handle = ACPI_ROOT_OBJECT; | 883 | status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device, |
884 | boot_ec, NULL); | ||
885 | if (ACPI_FAILURE(status)) | ||
886 | goto error; | ||
887 | } | ||
882 | 888 | ||
883 | ret = ec_install_handlers(boot_ec); | 889 | ret = ec_install_handlers(boot_ec); |
884 | if (!ret) { | 890 | if (!ret) { |