[PATCH v2 1/4] ACPI: EC: Add query notifier support

Armin Wolf
2023-02-25T11:51:58Z

Allow external drivers to register notifiers to act on
query events and possibly override the query handler.
Use the existing notifier infrastructure for this to
ensure correct locking.

Tested on a Acer Travelmate 4002WLMi.

Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
drivers/acpi/ec.c | 28 ++++++++++++++++++++++++----
drivers/acpi/internal.h | 5 +++++
2 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 105d2e795afa..dc7860a825a0 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -18,6 +18,7 @@

#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/notifier.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/delay.h>
@@ -184,6 +185,8 @@ static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */
static int EC_FLAGS_TRUST_DSDT_GPE; /* Needs DSDT GPE as correction setting */
static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */

+static BLOCKING_NOTIFIER_HEAD(acpi_ec_chain_head);
+
/* --------------------------------------------------------------------------
* Logging/Debugging
* -------------------------------------------------------------------------- */
@@ -1125,18 +1128,35 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
}
EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);

+int register_acpi_ec_query_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&acpi_ec_chain_head, nb);
+}
+EXPORT_SYMBOL_GPL(register_acpi_ec_query_notifier);
+
+int unregister_acpi_ec_query_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&acpi_ec_chain_head, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_acpi_ec_query_notifier);
+
static void acpi_ec_event_processor(struct work_struct *work)
{
struct acpi_ec_query *q = container_of(work, struct acpi_ec_query, work);
struct acpi_ec_query_handler *handler = q->handler;
struct acpi_ec *ec = q->ec;
+ int ret;

ec_dbg_evt("Query(0x%02x) started", handler->query_bit);

- if (handler->func)
- handler->func(handler->data);
- else if (handler->handle)
- acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
+ /* Allow notifier handlers to override query handlers */
+ ret = blocking_notifier_call_chain(&acpi_ec_chain_head, handler->query_bit, ec);
+ if (ret != NOTIFY_BAD) {
+ if (handler->func)
+ handler->func(handler->data);
+ else if (handler->handle)
+ acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
+ }

ec_dbg_evt("Query(0x%02x) stopped", handler->query_bit);

diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index ec584442fb29..6f41d42375ab 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -11,6 +11,8 @@

#include <linux/idr.h>

+struct notifier_block;
+
int early_acpi_osi_init(void);
int acpi_osi_init(void);
acpi_status acpi_os_initialize1(void);
@@ -212,6 +214,9 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
void *data);
void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit);

+int register_acpi_ec_query_notifier(struct notifier_block *nb);
+int unregister_acpi_ec_query_notifier(struct notifier_block *nb);
+
#ifdef CONFIG_PM_SLEEP
void acpi_ec_flush_work(void);
bool acpi_ec_dispatch_gpe(void);
--
2.30.2