[1/4] ACPI: EC: Add query notifier support
Commit Message
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(-)
--
2.30.2
@@ -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);
@@ -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);