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) { |
