aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/ec.c
diff options
context:
space:
mode:
authorAlexey Starikovskiy <alexey.y.starikovskiy@intel.com>2007-03-07 14:28:00 -0500
committerLen Brown <len.brown@intel.com>2007-03-09 23:27:28 -0500
commitc0900c3512dc8fd0b37f8fbcebc7853ed9efff10 (patch)
tree6a3a6b4e143f8cf8985d03390b678b295f660479 /drivers/acpi/ec.c
parente8284321048aac7be307b3ec5e0631f5c514935a (diff)
ACPI: EC: Clean ECDT and namespace parsing.
Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/ec.c')
-rw-r--r--drivers/acpi/ec.c205
1 files changed, 109 insertions, 96 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 399cedf2cfa6..c9dcf9a2a469 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -604,74 +604,73 @@ static int acpi_ec_remove_fs(struct acpi_device *device)
604/* -------------------------------------------------------------------------- 604/* --------------------------------------------------------------------------
605 Driver Interface 605 Driver Interface
606 -------------------------------------------------------------------------- */ 606 -------------------------------------------------------------------------- */
607static acpi_status
608ec_parse_io_ports(struct acpi_resource *resource, void *context);
609
610static acpi_status
611ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval);
612
613static struct acpi_ec *make_acpi_ec(void)
614{
615 struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
616 if (!ec)
617 return NULL;
618
619 atomic_set(&ec->query_pending, 0);
620 atomic_set(&ec->event_count, 1);
621 mutex_init(&ec->lock);
622 init_waitqueue_head(&ec->wait);
623
624 return ec;
625}
607 626
608static int acpi_ec_add(struct acpi_device *device) 627static int acpi_ec_add(struct acpi_device *device)
609{ 628{
610 int result = 0;
611 acpi_status status = AE_OK; 629 acpi_status status = AE_OK;
612 struct acpi_ec *ec = NULL; 630 struct acpi_ec *ec = NULL;
613 631
614 if (!device) 632 if (!device)
615 return -EINVAL; 633 return -EINVAL;
616 634
617 ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); 635 strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
636 strcpy(acpi_device_class(device), ACPI_EC_CLASS);
637
638 ec = make_acpi_ec();
618 if (!ec) 639 if (!ec)
619 return -ENOMEM; 640 return -ENOMEM;
620 641
621 ec->handle = device->handle; 642 status = ec_parse_device(device->handle, 0, ec, NULL);
622 ec->uid = -1; 643 if (status != AE_CTRL_TERMINATE) {
623 mutex_init(&ec->lock); 644 kfree(ec);
624 atomic_set(&ec->query_pending, 0); 645 return -EINVAL;
625 atomic_set(&ec->event_count, 1);
626 if (acpi_ec_mode == EC_INTR) {
627 init_waitqueue_head(&ec->wait);
628 } 646 }
629 strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
630 strcpy(acpi_device_class(device), ACPI_EC_CLASS);
631 acpi_driver_data(device) = ec;
632 647
633 /* Use the global lock for all EC transactions? */ 648 /* Check if we found the boot EC */
634 acpi_evaluate_integer(ec->handle, "_GLK", NULL, &ec->global_lock);
635
636 /* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
637 http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
638 if (ec_ecdt) { 649 if (ec_ecdt) {
639 acpi_remove_address_space_handler(ACPI_ROOT_OBJECT, 650 if (ec_ecdt->gpe == ec->gpe) {
640 ACPI_ADR_SPACE_EC, 651 /* We might have incorrect info for GL at boot time */
641 &acpi_ec_space_handler); 652 mutex_lock(&ec_ecdt->lock);
653 ec_ecdt->global_lock = ec->global_lock;
654 mutex_unlock(&ec_ecdt->lock);
655 kfree(ec);
656 ec = ec_ecdt;
657 }
658 }
642 659
643 acpi_remove_gpe_handler(NULL, ec_ecdt->gpe, 660 ec->handle = device->handle;
644 &acpi_ec_gpe_handler);
645 661
646 kfree(ec_ecdt); 662 acpi_driver_data(device) = ec;
647 }
648 663
649 /* Get GPE bit assignment (EC events). */ 664 if (!first_ec)
650 /* TODO: Add support for _GPE returning a package */ 665 first_ec = device;
651 status = acpi_evaluate_integer(ec->handle, "_GPE", NULL, &ec->gpe);
652 if (ACPI_FAILURE(status)) {
653 ACPI_EXCEPTION((AE_INFO, status,
654 "Obtaining GPE bit assignment"));
655 result = -ENODEV;
656 goto end;
657 }
658 666
659 result = acpi_ec_add_fs(device); 667 acpi_ec_add_fs(device);
660 if (result)
661 goto end;
662 668
663 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.", 669 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
664 acpi_device_name(device), acpi_device_bid(device), 670 acpi_device_name(device), acpi_device_bid(device),
665 (u32) ec->gpe)); 671 (u32) ec->gpe));
666 672
667 if (!first_ec) 673 return 0;
668 first_ec = device;
669
670 end:
671 if (result)
672 kfree(ec);
673
674 return result;
675} 674}
676 675
677static int acpi_ec_remove(struct acpi_device *device, int type) 676static int acpi_ec_remove(struct acpi_device *device, int type)
@@ -685,13 +684,19 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
685 684
686 acpi_ec_remove_fs(device); 685 acpi_ec_remove_fs(device);
687 686
688 kfree(ec); 687 acpi_driver_data(device) = NULL;
688 if (device == first_ec)
689 first_ec = NULL;
690
691 /* Don't touch boot EC */
692 if (ec_ecdt != ec)
693 kfree(ec);
689 694
690 return 0; 695 return 0;
691} 696}
692 697
693static acpi_status 698static acpi_status
694acpi_ec_io_ports(struct acpi_resource *resource, void *context) 699ec_parse_io_ports(struct acpi_resource *resource, void *context)
695{ 700{
696 struct acpi_ec *ec = context; 701 struct acpi_ec *ec = context;
697 702
@@ -717,9 +722,10 @@ acpi_ec_io_ports(struct acpi_resource *resource, void *context)
717 722
718static int ec_install_handlers(struct acpi_ec *ec) 723static int ec_install_handlers(struct acpi_ec *ec)
719{ 724{
720 acpi_status status = acpi_install_gpe_handler(NULL, ec->gpe, 725 acpi_status status;
721 ACPI_GPE_EDGE_TRIGGERED, 726 status = acpi_install_gpe_handler(NULL, ec->gpe,
722 &acpi_ec_gpe_handler, ec); 727 ACPI_GPE_EDGE_TRIGGERED,
728 &acpi_ec_gpe_handler, ec);
723 if (ACPI_FAILURE(status)) 729 if (ACPI_FAILURE(status))
724 return -ENODEV; 730 return -ENODEV;
725 acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME); 731 acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
@@ -739,8 +745,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
739 745
740static int acpi_ec_start(struct acpi_device *device) 746static int acpi_ec_start(struct acpi_device *device)
741{ 747{
742 acpi_status status = AE_OK; 748 struct acpi_ec *ec;
743 struct acpi_ec *ec = NULL;
744 749
745 if (!device) 750 if (!device)
746 return -EINVAL; 751 return -EINVAL;
@@ -750,32 +755,31 @@ static int acpi_ec_start(struct acpi_device *device)
750 if (!ec) 755 if (!ec)
751 return -EINVAL; 756 return -EINVAL;
752 757
753 /*
754 * Get I/O port addresses. Convert to GAS format.
755 */
756 status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS,
757 acpi_ec_io_ports, ec);
758 if (ACPI_FAILURE(status) || ec->command_addr == 0) {
759 ACPI_EXCEPTION((AE_INFO, status,
760 "Error getting I/O port addresses"));
761 return -ENODEV;
762 }
763
764 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx", 758 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
765 ec->gpe, ec->command_addr, ec->data_addr)); 759 ec->gpe, ec->command_addr, ec->data_addr));
766 760
761 /* Boot EC is already working */
762 if (ec == ec_ecdt)
763 return 0;
764
767 return ec_install_handlers(ec); 765 return ec_install_handlers(ec);
768} 766}
769 767
770static int acpi_ec_stop(struct acpi_device *device, int type) 768static int acpi_ec_stop(struct acpi_device *device, int type)
771{ 769{
772 acpi_status status = AE_OK; 770 acpi_status status;
773 struct acpi_ec *ec = NULL; 771 struct acpi_ec *ec;
774 772
775 if (!device) 773 if (!device)
776 return -EINVAL; 774 return -EINVAL;
777 775
778 ec = acpi_driver_data(device); 776 ec = acpi_driver_data(device);
777 if (!ec)
778 return -EINVAL;
779
780 /* Don't touch boot EC */
781 if (ec == ec_ecdt)
782 return 0;
779 783
780 status = acpi_remove_address_space_handler(ec->handle, 784 status = acpi_remove_address_space_handler(ec->handle,
781 ACPI_ADR_SPACE_EC, 785 ACPI_ADR_SPACE_EC,
@@ -790,51 +794,64 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
790 return 0; 794 return 0;
791} 795}
792 796
793static int __init acpi_ec_get_real_ecdt(void) 797static acpi_status
798ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
794{ 799{
795 acpi_status status; 800 acpi_status status;
801
802 struct acpi_ec *ec = context;
803 status = acpi_walk_resources(handle, METHOD_NAME__CRS,
804 ec_parse_io_ports, ec);
805 if (ACPI_FAILURE(status))
806 return status;
807
808 /* Get GPE bit assignment (EC events). */
809 /* TODO: Add support for _GPE returning a package */
810 status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
811 if (ACPI_FAILURE(status))
812 return status;
813
814 /* Use the global lock for all EC transactions? */
815 acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
816
817 ec->handle = handle;
818
819 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
820 ec->gpe, ec->command_addr, ec->data_addr));
821
822 return AE_CTRL_TERMINATE;
823}
824
825int __init acpi_ec_ecdt_probe(void)
826{
827 int ret;
828 acpi_status status;
796 struct acpi_table_ecdt *ecdt_ptr; 829 struct acpi_table_ecdt *ecdt_ptr;
797 830
831 ec_ecdt = make_acpi_ec();
832 if (!ec_ecdt)
833 return -ENOMEM;
834 /*
835 * Generate a boot ec context
836 */
837
798 status = acpi_get_table(ACPI_SIG_ECDT, 1, 838 status = acpi_get_table(ACPI_SIG_ECDT, 1,
799 (struct acpi_table_header **)&ecdt_ptr); 839 (struct acpi_table_header **)&ecdt_ptr);
800 if (ACPI_FAILURE(status)) 840 if (ACPI_FAILURE(status))
801 return -ENODEV; 841 goto error;
802 842
803 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT")); 843 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
804 844
805 /*
806 * Generate a temporary ec context to use until the namespace is scanned
807 */
808 ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
809 if (!ec_ecdt)
810 return -ENOMEM;
811
812 mutex_init(&ec_ecdt->lock);
813 atomic_set(&ec_ecdt->event_count, 1);
814 if (acpi_ec_mode == EC_INTR) {
815 init_waitqueue_head(&ec_ecdt->wait);
816 }
817 ec_ecdt->command_addr = ecdt_ptr->control.address; 845 ec_ecdt->command_addr = ecdt_ptr->control.address;
818 ec_ecdt->data_addr = ecdt_ptr->data.address; 846 ec_ecdt->data_addr = ecdt_ptr->data.address;
819 ec_ecdt->gpe = ecdt_ptr->gpe; 847 ec_ecdt->gpe = ecdt_ptr->gpe;
820 ec_ecdt->uid = ecdt_ptr->uid; 848 ec_ecdt->uid = ecdt_ptr->uid;
821
822 ec_ecdt->handle = ACPI_ROOT_OBJECT; 849 ec_ecdt->handle = ACPI_ROOT_OBJECT;
823 return 0;
824}
825
826int __init acpi_ec_ecdt_probe(void)
827{
828 int ret;
829
830 ret = acpi_ec_get_real_ecdt();
831 if (ret)
832 return 0;
833 850
834 ret = ec_install_handlers(ec_ecdt); 851 ret = ec_install_handlers(ec_ecdt);
835 if (!ret) 852 if (!ret)
836 return 0; 853 return 0;
837 854 error:
838 kfree(ec_ecdt); 855 kfree(ec_ecdt);
839 ec_ecdt = NULL; 856 ec_ecdt = NULL;
840 857
@@ -884,12 +901,8 @@ static int __init acpi_ec_set_intr_mode(char *str)
884 if (!get_option(&str, &intr)) 901 if (!get_option(&str, &intr))
885 return 0; 902 return 0;
886 903
887 if (intr) { 904 acpi_ec_mode = (intr) ? EC_INTR : EC_POLL;
888 acpi_ec_mode = EC_INTR; 905
889 } else {
890 acpi_ec_mode = EC_POLL;
891 }
892 acpi_ec_driver.ops.add = acpi_ec_add;
893 printk(KERN_NOTICE PREFIX "%s mode.\n", intr ? "interrupt" : "polling"); 906 printk(KERN_NOTICE PREFIX "%s mode.\n", intr ? "interrupt" : "polling");
894 907
895 return 1; 908 return 1;