[PATCH] ACPI: add internal event mechanism

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch creates a new event system for communication between in-kernel
ACPI drivers ("ievent"). It is simple - it should only be used to infrequently
pass simple messages to a small audience.

This is used in an upcoming patch which makes the ACPI video driver listen for
lid open events from the button driver. I hope it is generic enough to be
useful to other ACPI drivers in the future.

Signed-off-by: Daniel Drake <dsd@xxxxxxxxxx>

Index: linux/drivers/acpi/bus.c
===================================================================
--- linux.orig/drivers/acpi/bus.c
+++ linux/drivers/acpi/bus.c
@@ -533,6 +533,100 @@ static void acpi_bus_notify(acpi_handle 
 }
 
 /* --------------------------------------------------------------------------
+                             Internal events
+   -------------------------------------------------------------------------- */
+
+/*
+ * This is an event implementation designed for simple communication between
+ * ACPI drivers. It is intended for infrequent events that do not have
+ * many listeners.
+ *
+ * Drivers install an ievent handler to a certain event, and unregister it
+ * later. Drivers may raise (notify) events from any point except from the
+ * context of an event handler function.
+ */
+
+static struct list_head ievent_list;
+static spinlock_t ievent_lock;
+
+struct acpi_ievent_handle {
+	struct list_head list;
+	enum acpi_ievent_code event;
+	acpi_ievent_handler handler;
+	void *user_data;
+};
+
+/* Subscribe to a specific internal event.
+ *
+ * The handler function takes 3 parameters:
+ * 1. The acpi_ievent_code of the event that was raised
+ * 2. Some event data (set when the event was raised by the code which
+ *    raised the event)
+ * 3. Some user data which you can specify in the data parameter below.
+ *
+ * This function returns a handle which you must save so that you can
+ * unsubscribe later.
+ */
+struct acpi_ievent_handle *
+acpi_install_ievent_handler(enum acpi_ievent_code event,
+			    acpi_ievent_handler handler, void *data)
+{
+	unsigned long flags;
+	struct acpi_ievent_handle *handle
+		= kmalloc(sizeof(*handle), GFP_KERNEL);
+	if (!handle)
+		return NULL;
+
+	handle->event = event;
+	handle->handler = handler;
+	handle->user_data = data;
+	INIT_LIST_HEAD(&handle->list);
+
+	spin_lock_irqsave(&ievent_lock, flags);
+	list_add_tail(&handle->list, &ievent_list);
+	spin_unlock_irqrestore(&ievent_lock, flags);
+
+	return handle;
+}
+EXPORT_SYMBOL_GPL(acpi_install_ievent_handler);
+
+/*
+ * Unsubscribe from an internal event, using a handle that was returned from
+ * acpi_install_ievent_handler() earlier.
+ */
+void acpi_remove_ievent_handler(struct acpi_ievent_handle *handle)
+{
+	unsigned long flags;
+
+	if (!handle)
+		return;
+
+	spin_lock_irqsave(&ievent_lock, flags);
+	list_del(&handle->list);
+	spin_unlock_irqrestore(&ievent_lock, flags);
+	kfree(handle);
+}
+EXPORT_SYMBOL_GPL(acpi_remove_ievent_handler);
+
+/*
+ * Raise an event with some data.
+ */
+void acpi_ievent_notify(enum acpi_ievent_code event, void *event_data)
+{
+	struct acpi_ievent_handle *handle;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ievent_lock, flags);
+	list_for_each_entry(handle, &ievent_list, list) {
+		if (handle->event != event)
+			continue;
+		handle->handler(event, event_data, handle->user_data);
+	}
+	spin_unlock_irqrestore(&ievent_lock, flags);
+}
+EXPORT_SYMBOL_GPL(acpi_ievent_notify);
+
+/* --------------------------------------------------------------------------
                              Initialization/Cleanup
    -------------------------------------------------------------------------- */
 
@@ -741,6 +835,8 @@ static int __init acpi_init(void)
 {
 	int result = 0;
 
+	spin_lock_init(&ievent_lock);
+	INIT_LIST_HEAD(&ievent_list);
 
 	if (acpi_disabled) {
 		printk(KERN_INFO PREFIX "Interpreter disabled.\n");
Index: linux/include/acpi/acpi_bus.h
===================================================================
--- linux.orig/include/acpi/acpi_bus.h
+++ linux/include/acpi/acpi_bus.h
@@ -323,6 +323,26 @@ struct acpi_bus_event {
 extern struct kset acpi_subsys;
 
 /*
+ * Internal events
+ */
+
+enum acpi_ievent_code {
+	ACPI_IEVENT_LID,
+};
+
+struct acpi_ievent_handle;
+
+typedef
+void (*acpi_ievent_handler)(enum acpi_ievent_code event, void *event_data,
+			    void *user_data);
+
+struct acpi_ievent_handle *
+acpi_install_ievent_handler(enum acpi_ievent_code event,
+			    acpi_ievent_handler handler, void *data);
+void acpi_remove_ievent_handler(struct acpi_ievent_handle *handle);
+void acpi_ievent_notify(enum acpi_ievent_code event, void *event_data);
+
+/*
  * External Functions
  */
 
-
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux