Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ACPI EC: Add support for non-AML EC query handlers

Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
Signed-off-by: Len Brown <len.brown@intel.com>

authored by

Alexey Starikovskiy and committed by
Len Brown
837012ed 4350933a

+125 -50
+125 -50
drivers/acpi/ec.c
··· 34 34 #include <linux/proc_fs.h> 35 35 #include <linux/seq_file.h> 36 36 #include <linux/interrupt.h> 37 + #include <linux/list.h> 37 38 #include <asm/io.h> 38 39 #include <acpi/acpi_bus.h> 39 40 #include <acpi/acpi_drivers.h> ··· 44 43 #define ACPI_EC_HID "PNP0C09" 45 44 #define ACPI_EC_DEVICE_NAME "Embedded Controller" 46 45 #define ACPI_EC_FILE_INFO "info" 46 + 47 47 #undef PREFIX 48 48 #define PREFIX "ACPI: EC: " 49 49 ··· 62 60 ACPI_EC_BURST_DISABLE = 0x83, 63 61 ACPI_EC_COMMAND_QUERY = 0x84, 64 62 }; 63 + 65 64 /* EC events */ 66 65 enum ec_event { 67 66 ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ ··· 96 93 97 94 /* If we find an EC via the ECDT, we need to keep a ptr to its context */ 98 95 /* External interfaces use first EC only, so remember */ 96 + typedef int (*acpi_ec_query_func) (void *data); 97 + 98 + struct acpi_ec_query_handler { 99 + struct list_head node; 100 + acpi_ec_query_func func; 101 + acpi_handle handle; 102 + void *data; 103 + u8 query_bit; 104 + }; 105 + 99 106 static struct acpi_ec { 100 107 acpi_handle handle; 101 108 unsigned long gpe; ··· 116 103 atomic_t query_pending; 117 104 atomic_t event_count; 118 105 wait_queue_head_t wait; 106 + struct list_head list; 119 107 } *boot_ec, *first_ec; 120 108 121 109 /* -------------------------------------------------------------------------- ··· 407 393 /* -------------------------------------------------------------------------- 408 394 Event Management 409 395 -------------------------------------------------------------------------- */ 396 + int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, 397 + acpi_handle handle, acpi_ec_query_func func, 398 + void *data) 399 + { 400 + struct acpi_ec_query_handler *handler = 401 + kzalloc(sizeof(struct acpi_ec_query_handler), GFP_KERNEL); 402 + if (!handler) 403 + return -ENOMEM; 404 + 405 + handler->query_bit = query_bit; 406 + handler->handle = handle; 407 + handler->func = func; 408 + handler->data = data; 409 + mutex_lock(&ec->lock); 410 + list_add_tail(&handler->node, &ec->list); 411 + mutex_unlock(&ec->lock); 412 + return 0; 413 + } 414 + 415 + EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler); 416 + 417 + void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) 418 + { 419 + struct acpi_ec_query_handler *handler; 420 + mutex_lock(&ec->lock); 421 + list_for_each_entry(handler, &ec->list, node) { 422 + if (query_bit == handler->query_bit) { 423 + list_del(&handler->node); 424 + kfree(handler); 425 + break; 426 + } 427 + } 428 + mutex_unlock(&ec->lock); 429 + } 430 + 431 + EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); 410 432 411 433 static void acpi_ec_gpe_query(void *ec_cxt) 412 434 { 413 435 struct acpi_ec *ec = ec_cxt; 414 436 u8 value = 0; 415 - char object_name[8]; 437 + struct acpi_ec_query_handler *handler, copy; 416 438 417 439 if (!ec || acpi_ec_query(ec, &value)) 418 440 return; 419 - 420 - snprintf(object_name, 8, "_Q%2.2X", value); 421 - 422 - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name)); 423 - 424 - acpi_evaluate_object(ec->handle, object_name, NULL, NULL); 441 + mutex_lock(&ec->lock); 442 + list_for_each_entry(handler, &ec->list, node) { 443 + if (value == handler->query_bit) { 444 + /* have custom handler for this bit */ 445 + memcpy(&copy, handler, sizeof(copy)); 446 + mutex_unlock(&ec->lock); 447 + if (copy.func) { 448 + copy.func(copy.data); 449 + } else if (copy.handle) { 450 + acpi_evaluate_object(copy.handle, NULL, NULL, NULL); 451 + } 452 + return; 453 + } 454 + } 455 + mutex_unlock(&ec->lock); 456 + printk(KERN_ERR PREFIX "Handler for query 0x%x is not found!\n", value); 425 457 } 426 458 427 459 static u32 acpi_ec_gpe_handler(void *data) ··· 486 426 if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) { 487 427 atomic_set(&ec->query_pending, 1); 488 428 status = 489 - acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, 490 - ec); 429 + acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec); 491 430 } 492 431 493 432 return status == AE_OK ? ··· 633 574 static acpi_status 634 575 ec_parse_io_ports(struct acpi_resource *resource, void *context); 635 576 636 - static acpi_status 637 - ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval); 638 - 639 577 static struct acpi_ec *make_acpi_ec(void) 640 578 { 641 579 struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); ··· 643 587 atomic_set(&ec->event_count, 1); 644 588 mutex_init(&ec->lock); 645 589 init_waitqueue_head(&ec->wait); 590 + INIT_LIST_HEAD(&ec->list); 646 591 647 592 return ec; 648 593 } 649 594 595 + static acpi_status 596 + acpi_ec_register_query_methods(acpi_handle handle, u32 level, 597 + void *context, void **return_value) 598 + { 599 + struct acpi_namespace_node *node = handle; 600 + struct acpi_ec *ec = context; 601 + int value = 0; 602 + if (sscanf(node->name.ascii, "_Q%x", &value) == 1) { 603 + acpi_ec_add_query_handler(ec, value, handle, NULL, NULL); 604 + } 605 + return AE_OK; 606 + } 607 + 608 + static int ec_parse_device(struct acpi_ec *ec, acpi_handle handle) 609 + { 610 + if (ACPI_FAILURE(acpi_walk_resources(handle, METHOD_NAME__CRS, 611 + ec_parse_io_ports, ec))) 612 + return -EINVAL; 613 + 614 + /* Get GPE bit assignment (EC events). */ 615 + /* TODO: Add support for _GPE returning a package */ 616 + if (ACPI_FAILURE(acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe))) 617 + return -EINVAL; 618 + 619 + /* Use the global lock for all EC transactions? */ 620 + acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); 621 + 622 + /* Find and register all query methods */ 623 + acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1, 624 + acpi_ec_register_query_methods, ec, NULL); 625 + 626 + ec->handle = handle; 627 + 628 + printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx", 629 + ec->gpe, ec->command_addr, ec->data_addr); 630 + 631 + return 0; 632 + } 633 + 650 634 static int acpi_ec_add(struct acpi_device *device) 651 635 { 652 - acpi_status status = AE_OK; 653 636 struct acpi_ec *ec = NULL; 654 637 655 638 if (!device) ··· 701 606 if (!ec) 702 607 return -ENOMEM; 703 608 704 - status = ec_parse_device(device->handle, 0, ec, NULL); 705 - if (status != AE_CTRL_TERMINATE) { 609 + if (ec_parse_device(ec, device->handle)) { 706 610 kfree(ec); 707 611 return -EINVAL; 708 612 } ··· 712 618 /* We might have incorrect info for GL at boot time */ 713 619 mutex_lock(&boot_ec->lock); 714 620 boot_ec->global_lock = ec->global_lock; 621 + /* Copy handlers from new ec into boot ec */ 622 + list_splice(&ec->list, &boot_ec->list); 715 623 mutex_unlock(&boot_ec->lock); 716 624 kfree(ec); 717 625 ec = boot_ec; ··· 724 628 acpi_driver_data(device) = ec; 725 629 726 630 acpi_ec_add_fs(device); 727 - 728 631 return 0; 729 632 } 730 633 731 634 static int acpi_ec_remove(struct acpi_device *device, int type) 732 635 { 733 636 struct acpi_ec *ec; 637 + struct acpi_ec_query_handler *handler; 734 638 735 639 if (!device) 736 640 return -EINVAL; 737 641 738 642 ec = acpi_driver_data(device); 643 + mutex_lock(&ec->lock); 644 + list_for_each_entry(handler, &ec->list, node) { 645 + list_del(&handler->node); 646 + kfree(handler); 647 + } 648 + mutex_unlock(&ec->lock); 739 649 acpi_ec_remove_fs(device); 740 650 acpi_driver_data(device) = NULL; 741 651 if (ec == first_ec) ··· 797 695 return -ENODEV; 798 696 } 799 697 800 - /* EC is fully operational, allow queries */ 801 - atomic_set(&ec->query_pending, 0); 802 - 803 698 return 0; 804 699 } 805 700 806 701 static int acpi_ec_start(struct acpi_device *device) 807 702 { 808 703 struct acpi_ec *ec; 704 + int ret = 0; 809 705 810 706 if (!device) 811 707 return -EINVAL; ··· 814 714 return -EINVAL; 815 715 816 716 /* Boot EC is already working */ 817 - if (ec == boot_ec) 818 - return 0; 717 + if (ec != boot_ec) 718 + ret = ec_install_handlers(ec); 819 719 820 - return ec_install_handlers(ec); 720 + /* EC is fully operational, allow queries */ 721 + atomic_set(&ec->query_pending, 0); 722 + 723 + return ret; 821 724 } 822 725 823 726 static int acpi_ec_stop(struct acpi_device *device, int type) ··· 850 747 return -ENODEV; 851 748 852 749 return 0; 853 - } 854 - 855 - static acpi_status 856 - ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) 857 - { 858 - acpi_status status; 859 - 860 - struct acpi_ec *ec = context; 861 - status = acpi_walk_resources(handle, METHOD_NAME__CRS, 862 - ec_parse_io_ports, ec); 863 - if (ACPI_FAILURE(status)) 864 - return status; 865 - 866 - /* Get GPE bit assignment (EC events). */ 867 - /* TODO: Add support for _GPE returning a package */ 868 - status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe); 869 - if (ACPI_FAILURE(status)) 870 - return status; 871 - 872 - /* Use the global lock for all EC transactions? */ 873 - acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); 874 - 875 - ec->handle = handle; 876 - 877 - printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx", 878 - ec->gpe, ec->command_addr, ec->data_addr); 879 - 880 - return AE_CTRL_TERMINATE; 881 750 } 882 751 883 752 int __init acpi_ec_ecdt_probe(void)