aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/ec.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r--drivers/acpi/ec.c90
1 files changed, 39 insertions, 51 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index e9a04052084b..7b4178393e34 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -121,6 +121,7 @@ static struct acpi_ec {
121 atomic_t event_count; 121 atomic_t event_count;
122 wait_queue_head_t wait; 122 wait_queue_head_t wait;
123 struct list_head list; 123 struct list_head list;
124 u8 handlers_installed;
124} *boot_ec, *first_ec; 125} *boot_ec, *first_ec;
125 126
126/* -------------------------------------------------------------------------- 127/* --------------------------------------------------------------------------
@@ -679,32 +680,50 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
679 status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe); 680 status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
680 if (ACPI_FAILURE(status)) 681 if (ACPI_FAILURE(status))
681 return status; 682 return status;
682
683 /* Find and register all query methods */ 683 /* Find and register all query methods */
684 acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1, 684 acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1,
685 acpi_ec_register_query_methods, ec, NULL); 685 acpi_ec_register_query_methods, ec, NULL);
686
687 /* Use the global lock for all EC transactions? */ 686 /* Use the global lock for all EC transactions? */
688 acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); 687 acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
689
690 ec->handle = handle; 688 ec->handle = handle;
691
692 printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
693 ec->gpe, ec->command_addr, ec->data_addr);
694
695 return AE_CTRL_TERMINATE; 689 return AE_CTRL_TERMINATE;
696} 690}
697 691
692static void ec_remove_handlers(struct acpi_ec *ec)
693{
694 if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
695 ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
696 printk(KERN_ERR PREFIX "failed to remove space handler\n");
697 if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
698 &acpi_ec_gpe_handler)))
699 printk(KERN_ERR PREFIX "failed to remove gpe handler\n");
700 ec->handlers_installed = 0;
701}
702
698static int acpi_ec_add(struct acpi_device *device) 703static int acpi_ec_add(struct acpi_device *device)
699{ 704{
700 struct acpi_ec *ec = NULL; 705 struct acpi_ec *ec = NULL;
701 706
702 if (!device) 707 if (!device)
703 return -EINVAL; 708 return -EINVAL;
704
705 strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); 709 strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
706 strcpy(acpi_device_class(device), ACPI_EC_CLASS); 710 strcpy(acpi_device_class(device), ACPI_EC_CLASS);
707 711
712 /* Check for boot EC */
713 if (boot_ec) {
714 if (boot_ec->handle == device->handle) {
715 /* Pre-loaded EC from DSDT, just move pointer */
716 ec = boot_ec;
717 boot_ec = NULL;
718 goto end;
719 } else if (boot_ec->handle == ACPI_ROOT_OBJECT) {
720 /* ECDT-based EC, time to shut it down */
721 ec_remove_handlers(boot_ec);
722 kfree(boot_ec);
723 first_ec = boot_ec = NULL;
724 }
725 }
726
708 ec = make_acpi_ec(); 727 ec = make_acpi_ec();
709 if (!ec) 728 if (!ec)
710 return -ENOMEM; 729 return -ENOMEM;
@@ -714,25 +733,14 @@ static int acpi_ec_add(struct acpi_device *device)
714 kfree(ec); 733 kfree(ec);
715 return -EINVAL; 734 return -EINVAL;
716 } 735 }
717
718 /* Check if we found the boot EC */
719 if (boot_ec) {
720 if (boot_ec->gpe == ec->gpe) {
721 /* We might have incorrect info for GL at boot time */
722 mutex_lock(&boot_ec->lock);
723 boot_ec->global_lock = ec->global_lock;
724 /* Copy handlers from new ec into boot ec */
725 list_splice(&ec->list, &boot_ec->list);
726 mutex_unlock(&boot_ec->lock);
727 kfree(ec);
728 ec = boot_ec;
729 }
730 } else
731 first_ec = ec;
732 ec->handle = device->handle; 736 ec->handle = device->handle;
737 end:
738 if (!first_ec)
739 first_ec = ec;
733 acpi_driver_data(device) = ec; 740 acpi_driver_data(device) = ec;
734
735 acpi_ec_add_fs(device); 741 acpi_ec_add_fs(device);
742 printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
743 ec->gpe, ec->command_addr, ec->data_addr);
736 return 0; 744 return 0;
737} 745}
738 746
@@ -755,10 +763,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
755 acpi_driver_data(device) = NULL; 763 acpi_driver_data(device) = NULL;
756 if (ec == first_ec) 764 if (ec == first_ec)
757 first_ec = NULL; 765 first_ec = NULL;
758 766 kfree(ec);
759 /* Don't touch boot EC */
760 if (boot_ec != ec)
761 kfree(ec);
762 return 0; 767 return 0;
763} 768}
764 769
@@ -788,6 +793,8 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context)
788static int ec_install_handlers(struct acpi_ec *ec) 793static int ec_install_handlers(struct acpi_ec *ec)
789{ 794{
790 acpi_status status; 795 acpi_status status;
796 if (ec->handlers_installed)
797 return 0;
791 status = acpi_install_gpe_handler(NULL, ec->gpe, 798 status = acpi_install_gpe_handler(NULL, ec->gpe,
792 ACPI_GPE_EDGE_TRIGGERED, 799 ACPI_GPE_EDGE_TRIGGERED,
793 &acpi_ec_gpe_handler, ec); 800 &acpi_ec_gpe_handler, ec);
@@ -806,6 +813,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
806 return -ENODEV; 813 return -ENODEV;
807 } 814 }
808 815
816 ec->handlers_installed = 1;
809 return 0; 817 return 0;
810} 818}
811 819
@@ -822,41 +830,22 @@ static int acpi_ec_start(struct acpi_device *device)
822 if (!ec) 830 if (!ec)
823 return -EINVAL; 831 return -EINVAL;
824 832
825 /* Boot EC is already working */ 833 ret = ec_install_handlers(ec);
826 if (ec != boot_ec)
827 ret = ec_install_handlers(ec);
828 834
829 /* EC is fully operational, allow queries */ 835 /* EC is fully operational, allow queries */
830 atomic_set(&ec->query_pending, 0); 836 atomic_set(&ec->query_pending, 0);
831
832 return ret; 837 return ret;
833} 838}
834 839
835static int acpi_ec_stop(struct acpi_device *device, int type) 840static int acpi_ec_stop(struct acpi_device *device, int type)
836{ 841{
837 acpi_status status;
838 struct acpi_ec *ec; 842 struct acpi_ec *ec;
839
840 if (!device) 843 if (!device)
841 return -EINVAL; 844 return -EINVAL;
842
843 ec = acpi_driver_data(device); 845 ec = acpi_driver_data(device);
844 if (!ec) 846 if (!ec)
845 return -EINVAL; 847 return -EINVAL;
846 848 ec_remove_handlers(ec);
847 /* Don't touch boot EC */
848 if (ec == boot_ec)
849 return 0;
850
851 status = acpi_remove_address_space_handler(ec->handle,
852 ACPI_ADR_SPACE_EC,
853 &acpi_ec_space_handler);
854 if (ACPI_FAILURE(status))
855 return -ENODEV;
856
857 status = acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
858 if (ACPI_FAILURE(status))
859 return -ENODEV;
860 849
861 return 0; 850 return 0;
862} 851}
@@ -876,7 +865,7 @@ int __init acpi_ec_ecdt_probe(void)
876 status = acpi_get_table(ACPI_SIG_ECDT, 1, 865 status = acpi_get_table(ACPI_SIG_ECDT, 1,
877 (struct acpi_table_header **)&ecdt_ptr); 866 (struct acpi_table_header **)&ecdt_ptr);
878 if (ACPI_SUCCESS(status)) { 867 if (ACPI_SUCCESS(status)) {
879 printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n\n"); 868 printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n");
880 boot_ec->command_addr = ecdt_ptr->control.address; 869 boot_ec->command_addr = ecdt_ptr->control.address;
881 boot_ec->data_addr = ecdt_ptr->data.address; 870 boot_ec->data_addr = ecdt_ptr->data.address;
882 boot_ec->gpe = ecdt_ptr->gpe; 871 boot_ec->gpe = ecdt_ptr->gpe;
@@ -898,7 +887,6 @@ int __init acpi_ec_ecdt_probe(void)
898 error: 887 error:
899 kfree(boot_ec); 888 kfree(boot_ec);
900 boot_ec = NULL; 889 boot_ec = NULL;
901
902 return -ENODEV; 890 return -ENODEV;
903} 891}
904 892