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