[PATCH] hal: enable addon-acpi to support acpi generic netlink interface for acpi events

Yi Yang yi.y.yang at intel.com
Thu Nov 6 10:08:40 PST 2008


Hello,

Linux ACPI subsystem won't provide /proc/acpi/event interface as Linux ACPI maintainer
Len Brown's schedule in the future, so hal and acpi have to support new netlink interface.

This patch enables hal to support netlink interface when /proc/acpi/event isn't available,
please review and consider applying it, thanks.


Signed-off-by: Yi Yang <yi.y.yang at intel.com>
---
 Makefile.in                    |    1 
 configure                      |   41 +++++++
 configure.in                   |   13 ++
 hald/linux/addons/addon-acpi.c |  223 ++++++++++++++++++++++++++++++++++++++---
 4 files changed, 260 insertions(+), 18 deletions(-)

diff --git a/Makefile.in b/Makefile.in
index 1432046..2dadced 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -87,6 +87,7 @@ distuninstallcheck_listfiles = find . -type f -print
 distcleancheck_listfiles = find . -type f -print
 ACLOCAL = @ACLOCAL@
 ACPI_ACPID = @ACPI_ACPID@
+ACPI_NETLINK = @ACPI_NETLINK@
 ACPI_PROC = @ACPI_PROC@
 AMTAR = @AMTAR@
 AR = @AR@
diff --git a/configure b/configure
index 3ffad0a..9c9b0f9 100755
--- a/configure
+++ b/configure
@@ -901,6 +901,9 @@ ACPI_ACPID_FALSE
 ACPI_PROC
 ACPI_PROC_TRUE
 ACPI_PROC_FALSE
+ACPI_NETLINK
+ACPI_NETLINK_TRUE
+ACPI_NETLINK_FALSE
 BUILD_ACPI_IBM
 BUILD_ACPI_IBM_TRUE
 BUILD_ACPI_IBM_FALSE
@@ -1617,6 +1620,7 @@ Optional Features:
   --enable-gtk-doc        use gtk-doc to build documentation default=yes
   --disable-acpi-acpid    Do not use ACPI daemon event source
   --disable-acpi-proc     Do not use ACPI kernel-interface directly
+  --disable-acpi-netlink  Do not use ACPI generic netlink interface directly
   --enable-acpi-ibm       Forward IBM ACPI events
   --enable-acpi-toshiba   Forward Toshiba ACPI events
   --enable-parted         Use libparted
@@ -22015,6 +22019,30 @@ else
 fi
 
 
+# Check whether --enable-acpi-netlink was given.
+if test "${enable_acpi_netlink+set}" = set; then
+  enableval=$enable_acpi_netlink; acpi_netlink=$enableval
+else
+  acpi_netlink=yes
+fi
+
+if test "x$acpi_netlink" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define ACPI_NETLINK 1
+_ACEOF
+
+fi
+
+ if test x$acpi_netlink = xyes; then
+  ACPI_NETLINK_TRUE=
+  ACPI_NETLINK_FALSE='#'
+else
+  ACPI_NETLINK_TRUE='#'
+  ACPI_NETLINK_FALSE=
+fi
+
+
 # Check whether --enable-acpi-ibm was given.
 if test "${enable_acpi_ibm+set}" = set; then
   enableval=$enable_acpi_ibm; acpi_ibm=$enableval
@@ -25504,6 +25532,13 @@ echo "$as_me: error: conditional \"ACPI_PROC\" was never defined.
 Usually this means the macro was only invoked conditionally." >&2;}
    { (exit 1); exit 1; }; }
 fi
+if test -z "${ACPI_NETLINK_TRUE}" && test -z "${ACPI_NETLINK_FALSE}"; then
+  { { echo "$as_me:$LINENO: error: conditional \"ACPI_NETLINK\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"ACPI_NETLINK\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
 if test -z "${BUILD_ACPI_IBM_TRUE}" && test -z "${BUILD_ACPI_IBM_FALSE}"; then
   { { echo "$as_me:$LINENO: error: conditional \"BUILD_ACPI_IBM\" was never defined.
 Usually this means the macro was only invoked conditionally." >&5
@@ -26539,6 +26574,9 @@ ACPI_ACPID_FALSE!$ACPI_ACPID_FALSE$ac_delim
 ACPI_PROC!$ACPI_PROC$ac_delim
 ACPI_PROC_TRUE!$ACPI_PROC_TRUE$ac_delim
 ACPI_PROC_FALSE!$ACPI_PROC_FALSE$ac_delim
+ACPI_NETLINK!$ACPI_NETLINK$ac_delim
+ACPI_NETLINK_TRUE!$ACPI_NETLINK_TRUE$ac_delim
+ACPI_NETLINK_FALSE!$ACPI_NETLINK_FALSE$ac_delim
 BUILD_ACPI_IBM!$BUILD_ACPI_IBM$ac_delim
 BUILD_ACPI_IBM_TRUE!$BUILD_ACPI_IBM_TRUE$ac_delim
 BUILD_ACPI_IBM_FALSE!$BUILD_ACPI_IBM_FALSE$ac_delim
@@ -27303,8 +27341,9 @@ echo "
 
         OS backend:                       ${HALD_BACKEND}
 
-        use acpi kernel interface:        ${acpi_proc}
+        use acpi /proc interface:         ${acpi_proc}
         use acpid interface:              ${acpi_acpid}
+        use acpi genetlink interface:     ${acpi_netlink}
         use libusb:                       ${USE_LIBUSB}
         use libpci:                       ${USE_LIBPCI}
         use libparted:                    ${USE_PARTED}
diff --git a/configure.in b/configure.in
index e76ff51..ff4a689 100644
--- a/configure.in
+++ b/configure.in
@@ -211,6 +211,16 @@ fi
 AC_SUBST(ACPI_PROC)
 AM_CONDITIONAL(ACPI_PROC, [test x$acpi_proc = xyes])
 
+AC_ARG_ENABLE([acpi-netlink],
+	      AS_HELP_STRING([--disable-acpi-netlink],
+			     [Do not use ACPI generic netlink interface directly]),
+	      [acpi_netlink=$enableval], [acpi_netlink=yes])
+if test "x$acpi_netlink" = "xyes" ; then
+   AC_DEFINE(ACPI_NETLINK,1,[Use generic netlink interface for ACPI events])
+fi
+AC_SUBST(ACPI_NETLINK)
+AM_CONDITIONAL(ACPI_NETLINK, [test x$acpi_netlink = xyes])
+
 AC_ARG_ENABLE([acpi-ibm],
 	      AS_HELP_STRING([--enable-acpi-ibm], [Forward IBM ACPI events]),
 	      [acpi_ibm=$enableval], [acpi_ibm=no])
@@ -1071,8 +1081,9 @@ echo "
 
         OS backend:                       ${HALD_BACKEND}
 
-        use acpi kernel interface:        ${acpi_proc}
+        use acpi /proc interface:         ${acpi_proc}
         use acpid interface:              ${acpi_acpid}
+        use acpi genetlink interface:     ${acpi_netlink}
         use libusb:                       ${USE_LIBUSB}
         use libpci:                       ${USE_LIBPCI}
         use libparted:                    ${USE_PARTED}
diff --git a/hald/linux/addons/addon-acpi.c b/hald/linux/addons/addon-acpi.c
index ea4ad30..8b878e1 100644
--- a/hald/linux/addons/addon-acpi.c
+++ b/hald/linux/addons/addon-acpi.c
@@ -35,34 +35,195 @@
 #include <sys/un.h>
 #include <unistd.h>
 
+#ifdef ACPI_NETLINK
+#include <netinet/in.h>
+#include <linux/netlink.h>
+#include <linux/genetlink.h>
+#endif
+
 #include "libhal/libhal.h"
 
 #include "../../logger.h"
 #include "../../util_helper.h"
 
+typedef struct {
+	int type;
+	void * handle;
+} ACPI_EVENT_HANDLE;
+
+enum {
+	FILE_HANDLE,
+	FD_HANDLE
+};
+
+typedef void * (ACPI_EVENT_HANDLER)(char *, size_t, ACPI_EVENT_HANDLE *);
+
+static void close_handle(ACPI_EVENT_HANDLE * handle)
+{
+	if (handle->type == FILE_HANDLE) {
+		fclose((FILE *)(handle->handle));
+	} else if (handle->type == FD_HANDLE) {
+		close((int)(handle->handle));
+	}
+	free(handle);
+}
+
 #ifdef ACPI_PROC
-static FILE *
-acpi_get_event_fp_kernel (void)
+static ACPI_EVENT_HANDLE *
+acpi_get_event_handle_from_proc (void)
 {
 	FILE *fp = NULL;
+	ACPI_EVENT_HANDLE * event_handle;
 
 	fp = fopen ("/proc/acpi/event", "r");
 
-	if (fp == NULL)
+	if (fp == NULL) {
 		HAL_ERROR (("Cannot open /proc/acpi/event: %s", strerror (errno)));
+		return NULL;
+	}
+
+	event_handle = (ACPI_EVENT_HANDLE *)malloc(sizeof(event_handle));
+	if (event_handle == NULL) {
+		HAL_ERROR (("malloc: %s", strerror (errno)));
+		return NULL;
+	}
+
+	event_handle->type = FILE_HANDLE;
+	event_handle->handle = (void *)fp;
+
+	return event_handle;
+}
+
+static char *
+acpi_get_event_from_proc(char * event, size_t bufsize, ACPI_EVENT_HANDLE * event_handle)
+{
+	return fgets(event, bufsize, (FILE *)(event_handle->handle));
+}
+#endif
+
+
+#ifdef ACPI_NETLINK
+static ACPI_EVENT_HANDLE *
+acpi_get_event_handle_from_netlink(void)
+{
+	struct sockaddr_nl nl_sockaddr;
+	const int buffersize = 16 * 1024 * 1024;
+	int sd;
+	int ret;
+	ACPI_EVENT_HANDLE * event_handle;
+
+	memset(&nl_sockaddr, 0x00, sizeof(struct sockaddr_nl));
+	nl_sockaddr.nl_family = AF_NETLINK;
+	nl_sockaddr.nl_pid = getpid();
+	nl_sockaddr.nl_groups = 0xffffffff;
+
+	sd = socket(PF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+	if (sd < 0) {
+		HAL_ERROR (("socket: %s", strerror (errno)));
+		return NULL;
+	}
+
+	/* set receive buffersize */
+	setsockopt(sd, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize));
+
+	ret = bind(sd, (struct sockaddr *) &nl_sockaddr, sizeof(struct sockaddr_nl));
+	if (ret < 0) {
+		close(sd);
+		HAL_ERROR (("bind: %s", strerror (errno)));
+		return NULL;
+	}
 
-	return fp;
+	event_handle = (ACPI_EVENT_HANDLE *)malloc(sizeof(event_handle));
+	if (event_handle == NULL) {
+		HAL_ERROR (("malloc: %s", strerror (errno)));
+		return NULL;
+	}
+
+	event_handle->type = FD_HANDLE;
+	event_handle->handle = (void *)sd;
+
+	return event_handle;
+}
+
+typedef char acpi_device_class[20];
+struct acpi_genl_event {
+	acpi_device_class device_class;
+	char bus_id[15];
+	unsigned int type;
+	unsigned int data;
+};
+
+#define ACPI_GENL_VERSION 0x01
+
+/* attributes of acpi_genl_family */
+enum {
+	ACPI_GENL_ATTR_UNSPEC,
+	ACPI_GENL_ATTR_EVENT,   /* ACPI event info needed by user space */
+	__ACPI_GENL_ATTR_MAX,
+};
+#define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1)
+
+/* commands supported by the acpi_genl_family */
+enum {
+	ACPI_GENL_CMD_UNSPEC,
+	ACPI_GENL_CMD_EVENT,    /* kernel->user notifications for ACPI events */
+	__ACPI_GENL_CMD_MAX,
+};
+
+static char acpi_event_buf[1024];
+static char *
+acpi_get_event_from_netlink(char * event, size_t bufsize, ACPI_EVENT_HANDLE * event_handle)
+{
+	size_t len;
+	struct nlmsghdr *nlmsghdr = NULL;
+	struct genlmsghdr *genlmsghdr = NULL;
+	struct nlattr *nlattrhdr = NULL;
+	struct acpi_genl_event *acpi_event = NULL;
+	size_t attroffset;
+
+	len = recv((int)(event_handle->handle), acpi_event_buf, 1024, 0);
+	if (len <= 0) {
+		HAL_ERROR(("recv: %s\n", strerror(errno)));
+		return NULL;
+	}
+
+	nlmsghdr = (struct nlmsghdr *)acpi_event_buf;
+	genlmsghdr = (struct genlmsghdr *)(acpi_event_buf + NLMSG_HDRLEN);
+	if ((genlmsghdr->cmd != ACPI_GENL_CMD_EVENT) || (genlmsghdr->version != ACPI_GENL_VERSION)) {
+		HAL_DEBUG (("This event isn't what i want, so skip it.\n"));
+	}
+	attroffset = NLMSG_HDRLEN + GENL_HDRLEN;
+	if (attroffset < len) {
+		nlattrhdr = (struct nlattr *)(acpi_event_buf + attroffset);
+		if ((nlattrhdr->nla_type != ACPI_GENL_ATTR_EVENT)
+			|| (NLA_ALIGN(nlattrhdr->nla_len) != NLA_ALIGN(NLA_HDRLEN
+				+ sizeof(struct acpi_genl_event)))) {
+			HAL_DEBUG (("This attr isn't what i want, so skip it.\n"));
+		} else {
+			acpi_event = (struct acpi_genl_event *)(acpi_event_buf + attroffset + NLA_HDRLEN);
+		}
+		attroffset += NLA_ALIGN(nlattrhdr->nla_len);
+	}
+
+	if (attroffset < len) {
+		HAL_DEBUG (("Get multiple ACPI events once: len = %d\n", len));
+	}
+
+	sprintf(event, "%s %s %08x %08x", acpi_event->device_class, acpi_event->bus_id,
+			acpi_event->type, acpi_event->data);
+	return event;
 }
 #endif
 
 #ifdef ACPI_ACPID
-static FILE *
-acpi_get_event_fp_acpid (void)
+static ACPI_EVENT_HANDLE *
+acpi_get_event_handle_from_acpid (void)
 {
 	FILE *fp = NULL;
 
 	struct sockaddr_un addr;
 	int fd;
+	ACPI_EVENT_HANDLE * event_handle;
 
 	if( (fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0 ) {
 		HAL_ERROR (("Cannot create socket: %s", strerror (errno)));
@@ -76,16 +237,33 @@ acpi_get_event_fp_acpid (void)
 	if (connect (fd, (struct sockaddr *) &addr, sizeof addr) < 0) {
 		HAL_ERROR (("Cannot connect to acpid socket: %s", strerror (errno)));
 		close (fd);
+		return NULL;
 	} else {
 		fp = fdopen (fd, "r");
 
 		if (fp == NULL) {
 			HAL_ERROR (("fdopen failed: %s", strerror (errno)));
 			close (fd);
+			return NULL;
 		}
 	}
 
-	return fp;
+	event_handle = (ACPI_EVENT_HANDLE *)malloc(sizeof(event_handle));
+	if (event_handle == NULL) {
+		HAL_ERROR (("malloc: %s", strerror (errno)));
+		return NULL;
+	}
+
+	event_handle->type = FILE_HANDLE;
+	event_handle->handle = (void *)fp;
+
+	return event_handle;
+}
+
+static char *
+acpi_get_event_from_acpid(char * event, size_t bufsize, ACPI_EVENT_HANDLE * event_handle)
+{
+	return fgets(event, bufsize, (FILE *)(event_handle->handle));
 }
 #endif
 
@@ -173,7 +351,7 @@ handle_ibm_acpi_events (LibHalContext *ctx, int type, int event)
 #endif
 
 static void
-main_loop (LibHalContext *ctx, FILE *eventfp)
+main_loop (LibHalContext *ctx, ACPI_EVENT_HANDLE * event_handle, ACPI_EVENT_HANDLER get_acpi_event)
 {
 	unsigned int acpi_num1;
 	unsigned int acpi_num2;
@@ -184,7 +362,7 @@ main_loop (LibHalContext *ctx, FILE *eventfp)
 
 	dbus_error_init (&error);
 
-	while (fgets (event, sizeof event, eventfp))
+	while (get_acpi_event(event, sizeof event, event_handle))
 	{
 		HAL_DEBUG (("event is '%s'", event));
 
@@ -244,7 +422,7 @@ main_loop (LibHalContext *ctx, FILE *eventfp)
 		}
 	}
 
-	fclose (eventfp);
+	close_handle (event_handle);
 }
 
 int
@@ -252,7 +430,7 @@ main (int argc, char **argv)
 {
 	LibHalContext *ctx = NULL;
 	DBusError error;
-	FILE *eventfp;
+	ACPI_EVENT_HANDLE *event_handle;
 
 	hal_set_proc_title_init (argc, argv);
 
@@ -277,24 +455,37 @@ main (int argc, char **argv)
 
 #ifdef ACPI_PROC
 	/* If we can connect directly to the kernel then do so. */
-	eventfp = acpi_get_event_fp_kernel ();
+	event_handle = acpi_get_event_handle_from_proc();
 	drop_privileges (0);
 
-	if (eventfp) {
+	if (event_handle) {
 		hal_set_proc_title ("hald-addon-acpi: listening on acpi kernel interface /proc/acpi/event");
-		main_loop (ctx, eventfp);
+		main_loop (ctx, event_handle, acpi_get_event_from_proc);
 		HAL_ERROR (("Lost connection to kernel acpi event source - exiting"));
 		return 1;
 	}
 #endif
 
+#ifdef ACPI_NETLINK
+	/* If we can't open /proc/acpi/event then do so. */
+	event_handle = acpi_get_event_handle_from_netlink ();
+
+	if (event_handle) {
+		hal_set_proc_title ("hald-addon-acpi: listening on acpi generic netlink interface");
+		main_loop (ctx, event_handle, acpi_get_event_from_netlink);
+		HAL_ERROR (("Failed to open acpi generic netlink - exiting"));
+		return 1;
+	}
+#endif
+
+	/* acpid is our only one choice now */
 	while (1)
 	{
 #ifdef ACPI_ACPID
 		/* Else, try to use acpid. */
-		if ((eventfp = acpi_get_event_fp_acpid ())) {
+		if ((event_handle = acpi_get_event_handle_from_acpid ())) {
 			hal_set_proc_title ("hald-addon-acpi: listening on acpid socket /var/run/acpid.socket");
-			main_loop (ctx, eventfp);
+			main_loop (ctx, event_handle, acpi_get_event_from_acpid);
 			HAL_DEBUG (("Cannot connect to acpid event socket - retry connect"));
 		}
 #endif




More information about the hal mailing list