[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