diff options
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r-- | drivers/acpi/ec.c | 106 |
1 files changed, 50 insertions, 56 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 469f3f57f881..56bee9e065cf 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) |
@@ -665,30 +664,44 @@ acpi_ec_register_query_methods(acpi_handle handle, u32 level, | |||
665 | return AE_OK; | 664 | return AE_OK; |
666 | } | 665 | } |
667 | 666 | ||
668 | 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) | ||
669 | { | 669 | { |
670 | if (ACPI_FAILURE(acpi_walk_resources(handle, METHOD_NAME__CRS, | 670 | acpi_status status; |
671 | ec_parse_io_ports, ec))) | 671 | |
672 | 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; | ||
673 | 677 | ||
674 | /* Get GPE bit assignment (EC events). */ | 678 | /* Get GPE bit assignment (EC events). */ |
675 | /* TODO: Add support for _GPE returning a package */ | 679 | /* TODO: Add support for _GPE returning a package */ |
676 | if (ACPI_FAILURE(acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe))) | 680 | status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe); |
677 | return -EINVAL; | 681 | if (ACPI_FAILURE(status)) |
678 | 682 | return status; | |
679 | /* Use the global lock for all EC transactions? */ | ||
680 | acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); | ||
681 | 683 | ||
682 | /* Find and register all query methods */ | 684 | /* Find and register all query methods */ |
683 | acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1, | 685 | acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1, |
684 | acpi_ec_register_query_methods, ec, NULL); | 686 | acpi_ec_register_query_methods, ec, NULL); |
685 | 687 | ||
688 | /* Use the global lock for all EC transactions? */ | ||
689 | acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); | ||
690 | |||
686 | ec->handle = handle; | 691 | ec->handle = handle; |
687 | 692 | ||
688 | printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx", | 693 | 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); | 694 | ec->gpe, ec->command_addr, ec->data_addr); |
690 | 695 | ||
691 | return 0; | 696 | return AE_CTRL_TERMINATE; |
697 | } | ||
698 | |||
699 | static void ec_remove_handlers(struct acpi_ec *ec) | ||
700 | { | ||
701 | acpi_remove_address_space_handler(ec->handle, | ||
702 | ACPI_ADR_SPACE_EC, | ||
703 | &acpi_ec_space_handler); | ||
704 | acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler); | ||
692 | } | 705 | } |
693 | 706 | ||
694 | static int acpi_ec_add(struct acpi_device *device) | 707 | static int acpi_ec_add(struct acpi_device *device) |
@@ -705,7 +718,8 @@ static int acpi_ec_add(struct acpi_device *device) | |||
705 | if (!ec) | 718 | if (!ec) |
706 | return -ENOMEM; | 719 | return -ENOMEM; |
707 | 720 | ||
708 | if (ec_parse_device(ec, device->handle)) { | 721 | if (ec_parse_device(device->handle, 0, ec, NULL) != |
722 | AE_CTRL_TERMINATE) { | ||
709 | kfree(ec); | 723 | kfree(ec); |
710 | return -EINVAL; | 724 | return -EINVAL; |
711 | } | 725 | } |
@@ -713,16 +727,13 @@ static int acpi_ec_add(struct acpi_device *device) | |||
713 | /* Check if we found the boot EC */ | 727 | /* Check if we found the boot EC */ |
714 | if (boot_ec) { | 728 | if (boot_ec) { |
715 | if (boot_ec->gpe == ec->gpe) { | 729 | if (boot_ec->gpe == ec->gpe) { |
716 | /* We might have incorrect info for GL at boot time */ | 730 | ec_remove_handlers(boot_ec); |
717 | mutex_lock(&boot_ec->lock); | 731 | mutex_destroy(&boot_ec->lock); |
718 | boot_ec->global_lock = ec->global_lock; | 732 | kfree(boot_ec); |
719 | /* Copy handlers from new ec into boot ec */ | 733 | 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 | } | 734 | } |
725 | } else | 735 | } |
736 | if (!first_ec) | ||
726 | first_ec = ec; | 737 | first_ec = ec; |
727 | ec->handle = device->handle; | 738 | ec->handle = device->handle; |
728 | acpi_driver_data(device) = ec; | 739 | acpi_driver_data(device) = ec; |
@@ -734,14 +745,14 @@ static int acpi_ec_add(struct acpi_device *device) | |||
734 | static int acpi_ec_remove(struct acpi_device *device, int type) | 745 | static int acpi_ec_remove(struct acpi_device *device, int type) |
735 | { | 746 | { |
736 | struct acpi_ec *ec; | 747 | struct acpi_ec *ec; |
737 | struct acpi_ec_query_handler *handler; | 748 | struct acpi_ec_query_handler *handler, *tmp; |
738 | 749 | ||
739 | if (!device) | 750 | if (!device) |
740 | return -EINVAL; | 751 | return -EINVAL; |
741 | 752 | ||
742 | ec = acpi_driver_data(device); | 753 | ec = acpi_driver_data(device); |
743 | mutex_lock(&ec->lock); | 754 | mutex_lock(&ec->lock); |
744 | list_for_each_entry(handler, &ec->list, node) { | 755 | list_for_each_entry_safe(handler, tmp, &ec->list, node) { |
745 | list_del(&handler->node); | 756 | list_del(&handler->node); |
746 | kfree(handler); | 757 | kfree(handler); |
747 | } | 758 | } |
@@ -751,9 +762,6 @@ static int acpi_ec_remove(struct acpi_device *device, int type) | |||
751 | if (ec == first_ec) | 762 | if (ec == first_ec) |
752 | first_ec = NULL; | 763 | first_ec = NULL; |
753 | 764 | ||
754 | /* Don't touch boot EC */ | ||
755 | if (boot_ec != ec) | ||
756 | kfree(ec); | ||
757 | return 0; | 765 | return 0; |
758 | } | 766 | } |
759 | 767 | ||
@@ -817,9 +825,7 @@ static int acpi_ec_start(struct acpi_device *device) | |||
817 | if (!ec) | 825 | if (!ec) |
818 | return -EINVAL; | 826 | return -EINVAL; |
819 | 827 | ||
820 | /* Boot EC is already working */ | 828 | ret = ec_install_handlers(ec); |
821 | if (ec != boot_ec) | ||
822 | ret = ec_install_handlers(ec); | ||
823 | 829 | ||
824 | /* EC is fully operational, allow queries */ | 830 | /* EC is fully operational, allow queries */ |
825 | atomic_set(&ec->query_pending, 0); | 831 | atomic_set(&ec->query_pending, 0); |
@@ -829,7 +835,6 @@ static int acpi_ec_start(struct acpi_device *device) | |||
829 | 835 | ||
830 | static int acpi_ec_stop(struct acpi_device *device, int type) | 836 | static int acpi_ec_stop(struct acpi_device *device, int type) |
831 | { | 837 | { |
832 | acpi_status status; | ||
833 | struct acpi_ec *ec; | 838 | struct acpi_ec *ec; |
834 | 839 | ||
835 | if (!device) | 840 | if (!device) |
@@ -838,21 +843,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type) | |||
838 | ec = acpi_driver_data(device); | 843 | ec = acpi_driver_data(device); |
839 | if (!ec) | 844 | if (!ec) |
840 | return -EINVAL; | 845 | return -EINVAL; |
841 | 846 | 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; | 847 | return 0; |
857 | } | 848 | } |
858 | 849 | ||
@@ -868,18 +859,21 @@ int __init acpi_ec_ecdt_probe(void) | |||
868 | /* | 859 | /* |
869 | * Generate a boot ec context | 860 | * Generate a boot ec context |
870 | */ | 861 | */ |
871 | |||
872 | status = acpi_get_table(ACPI_SIG_ECDT, 1, | 862 | status = acpi_get_table(ACPI_SIG_ECDT, 1, |
873 | (struct acpi_table_header **)&ecdt_ptr); | 863 | (struct acpi_table_header **)&ecdt_ptr); |
874 | if (ACPI_FAILURE(status)) | 864 | if (ACPI_SUCCESS(status)) { |
875 | goto error; | 865 | printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n\n"); |
876 | 866 | boot_ec->command_addr = ecdt_ptr->control.address; | |
877 | printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n"); | 867 | boot_ec->data_addr = ecdt_ptr->data.address; |
878 | 868 | boot_ec->gpe = ecdt_ptr->gpe; | |
879 | boot_ec->command_addr = ecdt_ptr->control.address; | 869 | boot_ec->handle = ACPI_ROOT_OBJECT; |
880 | boot_ec->data_addr = ecdt_ptr->data.address; | 870 | } else { |
881 | boot_ec->gpe = ecdt_ptr->gpe; | 871 | printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n"); |
882 | boot_ec->handle = ACPI_ROOT_OBJECT; | 872 | status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device, |
873 | boot_ec, NULL); | ||
874 | if (ACPI_FAILURE(status)) | ||
875 | goto error; | ||
876 | } | ||
883 | 877 | ||
884 | ret = ec_install_handlers(boot_ec); | 878 | ret = ec_install_handlers(boot_ec); |
885 | if (!ret) { | 879 | if (!ret) { |