diff options
Diffstat (limited to 'drivers/acpi/ec.c')
-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) { |