diff options
-rw-r--r-- | drivers/acpi/ec.c | 43 |
1 files changed, 33 insertions, 10 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 3e19123bb183..87b9911c9039 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -105,6 +105,7 @@ struct acpi_ec_query_handler { | |||
105 | acpi_handle handle; | 105 | acpi_handle handle; |
106 | void *data; | 106 | void *data; |
107 | u8 query_bit; | 107 | u8 query_bit; |
108 | struct kref kref; | ||
108 | }; | 109 | }; |
109 | 110 | ||
110 | struct transaction { | 111 | struct transaction { |
@@ -580,6 +581,27 @@ static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data) | |||
580 | /* -------------------------------------------------------------------------- | 581 | /* -------------------------------------------------------------------------- |
581 | Event Management | 582 | Event Management |
582 | -------------------------------------------------------------------------- */ | 583 | -------------------------------------------------------------------------- */ |
584 | static struct acpi_ec_query_handler * | ||
585 | acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler) | ||
586 | { | ||
587 | if (handler) | ||
588 | kref_get(&handler->kref); | ||
589 | return handler; | ||
590 | } | ||
591 | |||
592 | static void acpi_ec_query_handler_release(struct kref *kref) | ||
593 | { | ||
594 | struct acpi_ec_query_handler *handler = | ||
595 | container_of(kref, struct acpi_ec_query_handler, kref); | ||
596 | |||
597 | kfree(handler); | ||
598 | } | ||
599 | |||
600 | static void acpi_ec_put_query_handler(struct acpi_ec_query_handler *handler) | ||
601 | { | ||
602 | kref_put(&handler->kref, acpi_ec_query_handler_release); | ||
603 | } | ||
604 | |||
583 | int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, | 605 | int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, |
584 | acpi_handle handle, acpi_ec_query_func func, | 606 | acpi_handle handle, acpi_ec_query_func func, |
585 | void *data) | 607 | void *data) |
@@ -595,6 +617,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, | |||
595 | handler->func = func; | 617 | handler->func = func; |
596 | handler->data = data; | 618 | handler->data = data; |
597 | mutex_lock(&ec->mutex); | 619 | mutex_lock(&ec->mutex); |
620 | kref_init(&handler->kref); | ||
598 | list_add(&handler->node, &ec->list); | 621 | list_add(&handler->node, &ec->list); |
599 | mutex_unlock(&ec->mutex); | 622 | mutex_unlock(&ec->mutex); |
600 | return 0; | 623 | return 0; |
@@ -604,15 +627,18 @@ EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler); | |||
604 | void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) | 627 | void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) |
605 | { | 628 | { |
606 | struct acpi_ec_query_handler *handler, *tmp; | 629 | struct acpi_ec_query_handler *handler, *tmp; |
630 | LIST_HEAD(free_list); | ||
607 | 631 | ||
608 | mutex_lock(&ec->mutex); | 632 | mutex_lock(&ec->mutex); |
609 | list_for_each_entry_safe(handler, tmp, &ec->list, node) { | 633 | list_for_each_entry_safe(handler, tmp, &ec->list, node) { |
610 | if (query_bit == handler->query_bit) { | 634 | if (query_bit == handler->query_bit) { |
611 | list_del(&handler->node); | 635 | list_del_init(&handler->node); |
612 | kfree(handler); | 636 | list_add(&handler->node, &free_list); |
613 | } | 637 | } |
614 | } | 638 | } |
615 | mutex_unlock(&ec->mutex); | 639 | mutex_unlock(&ec->mutex); |
640 | list_for_each_entry(handler, &free_list, node) | ||
641 | acpi_ec_put_query_handler(handler); | ||
616 | } | 642 | } |
617 | EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); | 643 | EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); |
618 | 644 | ||
@@ -628,14 +654,14 @@ static void acpi_ec_run(void *cxt) | |||
628 | else if (handler->handle) | 654 | else if (handler->handle) |
629 | acpi_evaluate_object(handler->handle, NULL, NULL, NULL); | 655 | acpi_evaluate_object(handler->handle, NULL, NULL, NULL); |
630 | pr_debug("##### Query(0x%02x) stopped #####\n", handler->query_bit); | 656 | pr_debug("##### Query(0x%02x) stopped #####\n", handler->query_bit); |
631 | kfree(handler); | 657 | acpi_ec_put_query_handler(handler); |
632 | } | 658 | } |
633 | 659 | ||
634 | static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) | 660 | static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) |
635 | { | 661 | { |
636 | u8 value = 0; | 662 | u8 value = 0; |
637 | int status; | 663 | int status; |
638 | struct acpi_ec_query_handler *handler, *copy; | 664 | struct acpi_ec_query_handler *handler; |
639 | 665 | ||
640 | status = acpi_ec_query_unlocked(ec, &value); | 666 | status = acpi_ec_query_unlocked(ec, &value); |
641 | if (data) | 667 | if (data) |
@@ -646,15 +672,12 @@ static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data) | |||
646 | list_for_each_entry(handler, &ec->list, node) { | 672 | list_for_each_entry(handler, &ec->list, node) { |
647 | if (value == handler->query_bit) { | 673 | if (value == handler->query_bit) { |
648 | /* have custom handler for this bit */ | 674 | /* have custom handler for this bit */ |
649 | copy = kmalloc(sizeof(*handler), GFP_KERNEL); | 675 | handler = acpi_ec_get_query_handler(handler); |
650 | if (!copy) | ||
651 | return -ENOMEM; | ||
652 | memcpy(copy, handler, sizeof(*copy)); | ||
653 | pr_debug("##### Query(0x%02x) scheduled #####\n", | 676 | pr_debug("##### Query(0x%02x) scheduled #####\n", |
654 | handler->query_bit); | 677 | handler->query_bit); |
655 | return acpi_os_execute((copy->func) ? | 678 | return acpi_os_execute((handler->func) ? |
656 | OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER, | 679 | OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER, |
657 | acpi_ec_run, copy); | 680 | acpi_ec_run, handler); |
658 | } | 681 | } |
659 | } | 682 | } |
660 | return 0; | 683 | return 0; |