diff options
| -rw-r--r-- | drivers/acpi/ec.c | 113 | 
1 files changed, 45 insertions, 68 deletions
| diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 469f3f57f881..2300d81bbc4e 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
| @@ -471,7 +471,6 @@ static void acpi_ec_gpe_query(void *ec_cxt) | |||
| 471 | } | 471 | } | 
| 472 | } | 472 | } | 
| 473 | mutex_unlock(&ec->lock); | 473 | mutex_unlock(&ec->lock); | 
| 474 | printk(KERN_ERR PREFIX "Handler for query 0x%x is not found!\n", value); | ||
| 475 | } | 474 | } | 
| 476 | 475 | ||
| 477 | static u32 acpi_ec_gpe_handler(void *data) | 476 | static u32 acpi_ec_gpe_handler(void *data) | 
| @@ -653,42 +652,39 @@ static struct acpi_ec *make_acpi_ec(void) | |||
| 653 | } | 652 | } | 
| 654 | 653 | ||
| 655 | static acpi_status | 654 | static acpi_status | 
| 656 | acpi_ec_register_query_methods(acpi_handle handle, u32 level, | 655 | ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) | 
| 657 | void *context, void **return_value) | ||
| 658 | { | 656 | { | 
| 659 | struct acpi_namespace_node *node = handle; | 657 | acpi_status status; | 
| 660 | struct acpi_ec *ec = context; | ||
| 661 | int value = 0; | ||
| 662 | if (sscanf(node->name.ascii, "_Q%x", &value) == 1) { | ||
| 663 | acpi_ec_add_query_handler(ec, value, handle, NULL, NULL); | ||
| 664 | } | ||
| 665 | return AE_OK; | ||
| 666 | } | ||
| 667 | 658 | ||
| 668 | static int ec_parse_device(struct acpi_ec *ec, acpi_handle handle) | 659 | struct acpi_ec *ec = context; | 
| 669 | { | 660 | status = acpi_walk_resources(handle, METHOD_NAME__CRS, | 
| 670 | if (ACPI_FAILURE(acpi_walk_resources(handle, METHOD_NAME__CRS, | 661 | ec_parse_io_ports, ec); | 
| 671 | ec_parse_io_ports, ec))) | 662 | if (ACPI_FAILURE(status)) | 
| 672 | return -EINVAL; | 663 | return status; | 
| 673 | 664 | ||
| 674 | /* Get GPE bit assignment (EC events). */ | 665 | /* Get GPE bit assignment (EC events). */ | 
| 675 | /* TODO: Add support for _GPE returning a package */ | 666 | /* TODO: Add support for _GPE returning a package */ | 
| 676 | if (ACPI_FAILURE(acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe))) | 667 | status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe); | 
| 677 | return -EINVAL; | 668 | if (ACPI_FAILURE(status)) | 
| 669 | return status; | ||
| 678 | 670 | ||
| 679 | /* Use the global lock for all EC transactions? */ | 671 | /* Use the global lock for all EC transactions? */ | 
| 680 | acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); | 672 | acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); | 
| 681 | 673 | ||
| 682 | /* Find and register all query methods */ | ||
| 683 | acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1, | ||
| 684 | acpi_ec_register_query_methods, ec, NULL); | ||
| 685 | |||
| 686 | ec->handle = handle; | 674 | ec->handle = handle; | 
| 687 | 675 | ||
| 688 | printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx", | 676 | printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n", | 
| 689 | ec->gpe, ec->command_addr, ec->data_addr); | 677 | ec->gpe, ec->command_addr, ec->data_addr); | 
| 690 | 678 | ||
| 691 | return 0; | 679 | return AE_CTRL_TERMINATE; | 
| 680 | } | ||
| 681 | |||
| 682 | static void ec_remove_handlers(struct acpi_ec *ec) | ||
| 683 | { | ||
| 684 | acpi_remove_address_space_handler(ec->handle, | ||
| 685 | ACPI_ADR_SPACE_EC, | ||
| 686 | &acpi_ec_space_handler); | ||
| 687 | acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); | ||
| 692 | } | 688 | } | 
| 693 | 689 | ||
| 694 | static int acpi_ec_add(struct acpi_device *device) | 690 | static int acpi_ec_add(struct acpi_device *device) | 
| @@ -705,7 +701,8 @@ static int acpi_ec_add(struct acpi_device *device) | |||
| 705 | if (!ec) | 701 | if (!ec) | 
| 706 | return -ENOMEM; | 702 | return -ENOMEM; | 
| 707 | 703 | ||
| 708 | if (ec_parse_device(ec, device->handle)) { | 704 | if (ec_parse_device(device->handle, 0, ec, NULL) != | 
| 705 | AE_CTRL_TERMINATE) { | ||
| 709 | kfree(ec); | 706 | kfree(ec); | 
| 710 | return -EINVAL; | 707 | return -EINVAL; | 
| 711 | } | 708 | } | 
| @@ -713,16 +710,13 @@ static int acpi_ec_add(struct acpi_device *device) | |||
| 713 | /* Check if we found the boot EC */ | 710 | /* Check if we found the boot EC */ | 
| 714 | if (boot_ec) { | 711 | if (boot_ec) { | 
| 715 | if (boot_ec->gpe == ec->gpe) { | 712 | if (boot_ec->gpe == ec->gpe) { | 
| 716 | /* We might have incorrect info for GL at boot time */ | 713 | ec_remove_handlers(boot_ec); | 
| 717 | mutex_lock(&boot_ec->lock); | 714 | mutex_destroy(&boot_ec->lock); | 
| 718 | boot_ec->global_lock = ec->global_lock; | 715 | kfree(boot_ec); | 
| 719 | /* Copy handlers from new ec into boot ec */ | 716 | first_ec = boot_ec = NULL; | 
| 720 | list_splice(&ec->list, &boot_ec->list); | ||
| 721 | mutex_unlock(&boot_ec->lock); | ||
| 722 | kfree(ec); | ||
| 723 | ec = boot_ec; | ||
| 724 | } | 717 | } | 
| 725 | } else | 718 | } | 
| 719 | if (!first_ec) | ||
| 726 | first_ec = ec; | 720 | first_ec = ec; | 
| 727 | ec->handle = device->handle; | 721 | ec->handle = device->handle; | 
| 728 | acpi_driver_data(device) = ec; | 722 | acpi_driver_data(device) = ec; | 
| @@ -734,14 +728,14 @@ static int acpi_ec_add(struct acpi_device *device) | |||
| 734 | static int acpi_ec_remove(struct acpi_device *device, int type) | 728 | static int acpi_ec_remove(struct acpi_device *device, int type) | 
| 735 | { | 729 | { | 
| 736 | struct acpi_ec *ec; | 730 | struct acpi_ec *ec; | 
| 737 | struct acpi_ec_query_handler *handler; | 731 | struct acpi_ec_query_handler *handler, *tmp; | 
| 738 | 732 | ||
| 739 | if (!device) | 733 | if (!device) | 
| 740 | return -EINVAL; | 734 | return -EINVAL; | 
| 741 | 735 | ||
| 742 | ec = acpi_driver_data(device); | 736 | ec = acpi_driver_data(device); | 
| 743 | mutex_lock(&ec->lock); | 737 | mutex_lock(&ec->lock); | 
| 744 | list_for_each_entry(handler, &ec->list, node) { | 738 | list_for_each_entry_safe(handler, tmp, &ec->list, node) { | 
| 745 | list_del(&handler->node); | 739 | list_del(&handler->node); | 
| 746 | kfree(handler); | 740 | kfree(handler); | 
| 747 | } | 741 | } | 
| @@ -751,9 +745,6 @@ static int acpi_ec_remove(struct acpi_device *device, int type) | |||
| 751 | if (ec == first_ec) | 745 | if (ec == first_ec) | 
| 752 | first_ec = NULL; | 746 | first_ec = NULL; | 
| 753 | 747 | ||
| 754 | /* Don't touch boot EC */ | ||
| 755 | if (boot_ec != ec) | ||
| 756 | kfree(ec); | ||
| 757 | return 0; | 748 | return 0; | 
| 758 | } | 749 | } | 
| 759 | 750 | ||
| @@ -817,9 +808,7 @@ static int acpi_ec_start(struct acpi_device *device) | |||
| 817 | if (!ec) | 808 | if (!ec) | 
| 818 | return -EINVAL; | 809 | return -EINVAL; | 
| 819 | 810 | ||
| 820 | /* Boot EC is already working */ | 811 | ret = ec_install_handlers(ec); | 
| 821 | if (ec != boot_ec) | ||
| 822 | ret = ec_install_handlers(ec); | ||
| 823 | 812 | ||
| 824 | /* EC is fully operational, allow queries */ | 813 | /* EC is fully operational, allow queries */ | 
| 825 | atomic_set(&ec->query_pending, 0); | 814 | atomic_set(&ec->query_pending, 0); | 
| @@ -829,7 +818,6 @@ static int acpi_ec_start(struct acpi_device *device) | |||
| 829 | 818 | ||
| 830 | static int acpi_ec_stop(struct acpi_device *device, int type) | 819 | static int acpi_ec_stop(struct acpi_device *device, int type) | 
| 831 | { | 820 | { | 
| 832 | acpi_status status; | ||
| 833 | struct acpi_ec *ec; | 821 | struct acpi_ec *ec; | 
| 834 | 822 | ||
| 835 | if (!device) | 823 | if (!device) | 
| @@ -838,21 +826,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type) | |||
| 838 | ec = acpi_driver_data(device); | 826 | ec = acpi_driver_data(device); | 
| 839 | if (!ec) | 827 | if (!ec) | 
| 840 | return -EINVAL; | 828 | return -EINVAL; | 
| 841 | 829 | ec_remove_handlers(ec); | |
| 842 | /* Don't touch boot EC */ | ||
| 843 | if (ec == boot_ec) | ||
| 844 | return 0; | ||
| 845 | |||
| 846 | status = acpi_remove_address_space_handler(ec->handle, | ||
| 847 | ACPI_ADR_SPACE_EC, | ||
| 848 | &acpi_ec_space_handler); | ||
| 849 | if (ACPI_FAILURE(status)) | ||
| 850 | return -ENODEV; | ||
| 851 | |||
| 852 | status = acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); | ||
| 853 | if (ACPI_FAILURE(status)) | ||
| 854 | return -ENODEV; | ||
| 855 | |||
| 856 | return 0; | 830 | return 0; | 
| 857 | } | 831 | } | 
| 858 | 832 | ||
| @@ -868,18 +842,21 @@ int __init acpi_ec_ecdt_probe(void) | |||
| 868 | /* | 842 | /* | 
| 869 | * Generate a boot ec context | 843 | * Generate a boot ec context | 
| 870 | */ | 844 | */ | 
| 871 | |||
| 872 | status = acpi_get_table(ACPI_SIG_ECDT, 1, | 845 | status = acpi_get_table(ACPI_SIG_ECDT, 1, | 
| 873 | (struct acpi_table_header **)&ecdt_ptr); | 846 | (struct acpi_table_header **)&ecdt_ptr); | 
| 874 | if (ACPI_FAILURE(status)) | 847 | if (ACPI_SUCCESS(status)) { | 
| 875 | goto error; | 848 | printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n\n"); | 
| 876 | 849 | boot_ec->command_addr = ecdt_ptr->control.address; | |
| 877 | printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n"); | 850 | boot_ec->data_addr = ecdt_ptr->data.address; | 
| 878 | 851 | boot_ec->gpe = ecdt_ptr->gpe; | |
| 879 | boot_ec->command_addr = ecdt_ptr->control.address; | 852 | boot_ec->handle = ACPI_ROOT_OBJECT; | 
| 880 | boot_ec->data_addr = ecdt_ptr->data.address; | 853 | } else { | 
| 881 | boot_ec->gpe = ecdt_ptr->gpe; | 854 | printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n"); | 
| 882 | boot_ec->handle = ACPI_ROOT_OBJECT; | 855 | status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device, | 
| 856 | boot_ec, NULL); | ||
| 857 | if (ACPI_FAILURE(status)) | ||
| 858 | goto error; | ||
| 859 | } | ||
| 883 | 860 | ||
| 884 | ret = ec_install_handlers(boot_ec); | 861 | ret = ec_install_handlers(boot_ec); | 
| 885 | if (!ret) { | 862 | if (!ret) { | 
