Hotplug: Add HAL support
Add support for HAL-based hotplugging, in which we just get the list of input devices and properties from HAL. Requires an FDI which is not yet in mainline HAL.
This commit is contained in:
parent
aa75b34817
commit
8658f5d923
|
@ -16,4 +16,8 @@ noinst_LIBRARIES = libconfig.a
|
|||
libconfig_a_SOURCES += dbus.c
|
||||
endif
|
||||
|
||||
EXTRA_DIST = xorg-server.conf
|
||||
if CONFIG_HAL
|
||||
libconfig_a_SOURCES += hal.c
|
||||
endif
|
||||
|
||||
EXTRA_DIST = xorg-server.conf x11-input.fdi
|
||||
|
|
|
@ -50,3 +50,8 @@ void config_dbus_core_remove_hook(struct config_dbus_core_hook *hook);
|
|||
int config_dbus_init(void);
|
||||
void config_dbus_fini(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HAL
|
||||
int config_hal_init(void);
|
||||
void config_hal_fini(void);
|
||||
#endif
|
||||
|
|
|
@ -31,10 +31,16 @@
|
|||
void
|
||||
config_init()
|
||||
{
|
||||
#if defined(CONFIG_DBUS_API)
|
||||
#if defined(CONFIG_DBUS_API) || defined(CONFIG_HAL)
|
||||
if (config_dbus_core_init()) {
|
||||
# ifdef CONFIG_DBUS_API
|
||||
if (!config_dbus_init())
|
||||
ErrorF("[config] failed to initialise D-Bus API\n");
|
||||
# endif
|
||||
# ifdef CONFIG_HAL
|
||||
if (!config_hal_init())
|
||||
ErrorF("[config] failed to initialise HAL\n");
|
||||
# endif
|
||||
}
|
||||
else {
|
||||
ErrorF("[config] failed to initialise D-Bus core\n");
|
||||
|
@ -45,8 +51,13 @@ config_init()
|
|||
void
|
||||
config_fini()
|
||||
{
|
||||
#if defined(CONFIG_DBUS_API)
|
||||
#if defined(CONFIG_DBUS_API) || defined(CONFIG_HAL)
|
||||
# ifdef CONFIG_HAL
|
||||
config_hal_fini();
|
||||
# endif
|
||||
# ifdef CONFIG_DBUS_API
|
||||
config_dbus_fini();
|
||||
# endif
|
||||
config_dbus_core_fini();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -0,0 +1,369 @@
|
|||
/*
|
||||
* Copyright © 2006-2007 Daniel Stone
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders and/or authors
|
||||
* not be used in advertising or publicity pertaining to distribution of the
|
||||
* software without specific, written prior permission. The copyright holders
|
||||
* and/or authors make no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express or
|
||||
* implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS AND/OR AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD
|
||||
* TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND/OR AUTHORS BE LIABLE
|
||||
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include <hal/libhal.h>
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include "input.h"
|
||||
#include "inputstr.h"
|
||||
#include "hotplug.h"
|
||||
#include "config-backends.h"
|
||||
#include "os.h"
|
||||
|
||||
#define TYPE_NONE 0
|
||||
#define TYPE_KEYS 1
|
||||
#define TYPE_POINTER 2
|
||||
|
||||
struct config_hal_info {
|
||||
DBusConnection *system_bus;
|
||||
LibHalContext *hal_ctx;
|
||||
};
|
||||
|
||||
static void
|
||||
remove_device(DeviceIntPtr dev)
|
||||
{
|
||||
DebugF("[config/hal] removing device %s\n", dev->name);
|
||||
|
||||
/* Call PIE here so we don't try to dereference a device that's
|
||||
* already been removed. */
|
||||
OsBlockSignals();
|
||||
ProcessInputEvents();
|
||||
DeleteInputDeviceRequest(dev);
|
||||
OsReleaseSignals();
|
||||
}
|
||||
|
||||
static void
|
||||
device_removed(LibHalContext *ctx, const char *udi)
|
||||
{
|
||||
DeviceIntPtr dev;
|
||||
char *value;
|
||||
|
||||
value = xalloc(strlen(udi) + 5); /* "hal:" + NULL */
|
||||
if (!value)
|
||||
return;
|
||||
sprintf(value, "hal:%s", udi);
|
||||
|
||||
for (dev = inputInfo.devices; dev; dev = dev->next) {
|
||||
if (dev->config_info && strcmp(dev->config_info, value) == 0)
|
||||
remove_device(dev);
|
||||
}
|
||||
for (dev = inputInfo.off_devices; dev; dev = dev->next) {
|
||||
if (dev->config_info && strcmp(dev->config_info, value) == 0)
|
||||
remove_device(dev);
|
||||
}
|
||||
|
||||
xfree(value);
|
||||
}
|
||||
|
||||
static void
|
||||
add_option(InputOption **options, const char *key, const char *value)
|
||||
{
|
||||
if (!value || *value == '\0')
|
||||
return;
|
||||
|
||||
for (; *options; options = &(*options)->next)
|
||||
;
|
||||
*options = xcalloc(sizeof(**options), 1);
|
||||
(*options)->key = xstrdup(key);
|
||||
(*options)->value = xstrdup(value);
|
||||
(*options)->next = NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_prop_string(LibHalContext *hal_ctx, const char *udi, const char *name,
|
||||
DBusError *error)
|
||||
{
|
||||
char *prop, *ret;
|
||||
|
||||
prop = libhal_device_get_property_string(hal_ctx, udi, name, error);
|
||||
DebugF(" [config/hal] getting %s on %s returned %s\n", name, udi, prop);
|
||||
if (prop) {
|
||||
ret = xstrdup(prop);
|
||||
libhal_free_string(prop);
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_prop_string_array(LibHalContext *hal_ctx, const char *udi, const char *prop,
|
||||
DBusError *error)
|
||||
{
|
||||
char **props, *ret, *str;
|
||||
int i, len = 0;
|
||||
|
||||
props = libhal_device_get_property_strlist(hal_ctx, udi, prop, error);
|
||||
if (props) {
|
||||
for (i = 0; props[i]; i++)
|
||||
len += strlen(props[i]);
|
||||
|
||||
ret = xcalloc(sizeof(char), len + i); /* i - 1 commas, 1 NULL */
|
||||
if (!ret) {
|
||||
libhal_free_string_array(props);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
str = ret;
|
||||
for (i = 0; props[i]; i++) {
|
||||
str = strcpy(str, props[i]);
|
||||
*str++ = ',';
|
||||
}
|
||||
*str = '\0';
|
||||
|
||||
libhal_free_string_array(props);
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
device_added(LibHalContext *hal_ctx, const char *udi)
|
||||
{
|
||||
char **props;
|
||||
char *path = NULL, *driver = NULL, *name = NULL, *xkb_rules = NULL;
|
||||
char *xkb_model = NULL, *xkb_layout = NULL, *xkb_variant = NULL;
|
||||
char *xkb_options = NULL, *config_info = NULL;
|
||||
InputOption *options = NULL;
|
||||
DeviceIntPtr dev;
|
||||
DBusError error;
|
||||
int type = TYPE_NONE;
|
||||
int i;
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
props = libhal_device_get_property_strlist(hal_ctx, udi,
|
||||
"info.capabilities", &error);
|
||||
if (!props) {
|
||||
DebugF("[config/hal] couldn't get capabilities for %s: %s (%s)\n",
|
||||
udi, error.name, error.message);
|
||||
goto out_error;
|
||||
}
|
||||
for (i = 0; props[i]; i++) {
|
||||
/* input.keys is the new, of which input.keyboard is a subset, but
|
||||
* input.keyboard is the old 'we have keys', so we have to keep it
|
||||
* around. */
|
||||
if (strcmp(props[i], "input.keys") == 0 ||
|
||||
strcmp(props[i], "input.keyboard") == 0)
|
||||
type |= TYPE_KEYS;
|
||||
if (strcmp(props[i], "input.mouse") == 0)
|
||||
type |= TYPE_POINTER;
|
||||
}
|
||||
libhal_free_string_array(props);
|
||||
|
||||
if (type == TYPE_NONE)
|
||||
goto out_error;
|
||||
|
||||
driver = get_prop_string(hal_ctx, udi, "input.x11_driver", &error);
|
||||
path = get_prop_string(hal_ctx, udi, "input.device", &error);
|
||||
if (!driver || !path) {
|
||||
DebugF("[config/hal] no driver or path specified for %s\n", udi);
|
||||
goto unwind;
|
||||
}
|
||||
name = get_prop_string(hal_ctx, udi, "info.product", &error);
|
||||
if (!name)
|
||||
name = xstrdup("(unnamed)");
|
||||
|
||||
if (type & TYPE_KEYS) {
|
||||
xkb_rules = get_prop_string(hal_ctx, udi, "input.xkb_rules", &error);
|
||||
xkb_model = get_prop_string(hal_ctx, udi, "input.xkb_model", &error);
|
||||
xkb_layout = get_prop_string(hal_ctx, udi, "input.xkb_layout", &error);
|
||||
xkb_variant = get_prop_string(hal_ctx, udi, "input.xkb_variant",
|
||||
&error);
|
||||
xkb_options = get_prop_string_array(hal_ctx, udi, "input.xkb_options",
|
||||
&error);
|
||||
}
|
||||
|
||||
options = xcalloc(sizeof(*options), 1);
|
||||
options->key = xstrdup("_source");
|
||||
options->value = xstrdup("server/hal");
|
||||
if (!options->key || !options->value) {
|
||||
ErrorF("[config] couldn't allocate first key/value pair\n");
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
add_option(&options, "path", path);
|
||||
add_option(&options, "driver", driver);
|
||||
add_option(&options, "name", name);
|
||||
config_info = xalloc(strlen(udi) + 5); /* "hal:" and NULL */
|
||||
if (!config_info)
|
||||
goto unwind;
|
||||
sprintf(config_info, "hal:%s", udi);
|
||||
|
||||
if (xkb_model)
|
||||
add_option(&options, "xkb_model", xkb_model);
|
||||
if (xkb_layout)
|
||||
add_option(&options, "xkb_layout", xkb_layout);
|
||||
if (xkb_variant)
|
||||
add_option(&options, "xkb_variant", xkb_variant);
|
||||
if (xkb_options)
|
||||
add_option(&options, "xkb_options", xkb_options);
|
||||
|
||||
if (NewInputDeviceRequest(options, &dev) != Success) {
|
||||
DebugF("[config/hal] NewInputDeviceRequest failed\n");
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
for (; dev; dev = dev->next)
|
||||
dev->config_info = xstrdup(config_info);
|
||||
|
||||
unwind:
|
||||
if (path)
|
||||
xfree(path);
|
||||
if (driver)
|
||||
xfree(driver);
|
||||
if (name)
|
||||
xfree(name);
|
||||
if (xkb_rules)
|
||||
xfree(xkb_rules);
|
||||
if (xkb_model)
|
||||
xfree(xkb_model);
|
||||
if (xkb_layout)
|
||||
xfree(xkb_layout);
|
||||
if (xkb_options)
|
||||
xfree(xkb_options);
|
||||
if (config_info)
|
||||
xfree(config_info);
|
||||
|
||||
out_error:
|
||||
dbus_error_free(&error);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_hook(void *data)
|
||||
{
|
||||
DBusError error;
|
||||
struct config_hal_info *info = data;
|
||||
|
||||
if (info->hal_ctx) {
|
||||
dbus_error_init(&error);
|
||||
if (!libhal_ctx_shutdown(info->hal_ctx, &error))
|
||||
DebugF("[config/hal] couldn't shut down context?\n");
|
||||
libhal_ctx_free(info->hal_ctx);
|
||||
dbus_error_free(&error);
|
||||
}
|
||||
|
||||
info->hal_ctx = NULL;
|
||||
info->system_bus = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
connect_hook(DBusConnection *connection, void *data)
|
||||
{
|
||||
DBusError error;
|
||||
struct config_hal_info *info = data;
|
||||
char **devices;
|
||||
int num_devices, i;
|
||||
|
||||
info->system_bus = connection;
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
if (!info->hal_ctx)
|
||||
info->hal_ctx = libhal_ctx_new();
|
||||
if (!info->hal_ctx) {
|
||||
ErrorF("[config/hal] couldn't create HAL context\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (!libhal_ctx_set_dbus_connection(info->hal_ctx, info->system_bus)) {
|
||||
ErrorF("[config/hal] couldn't associate HAL context with bus\n");
|
||||
goto out_ctx;
|
||||
}
|
||||
if (!libhal_ctx_init(info->hal_ctx, &error)) {
|
||||
ErrorF("[config/hal] couldn't initialise context: %s (%s)\n",
|
||||
error.name, error.message);
|
||||
goto out_ctx;
|
||||
}
|
||||
if (!libhal_device_property_watch_all(info->hal_ctx, &error)) {
|
||||
ErrorF("[config/hal] couldn't watch all properties: %s (%s)\n",
|
||||
error.name, error.message);
|
||||
goto out_ctx2;
|
||||
}
|
||||
libhal_ctx_set_device_added(info->hal_ctx, device_added);
|
||||
libhal_ctx_set_device_removed(info->hal_ctx, device_removed);
|
||||
|
||||
devices = libhal_find_device_by_capability(info->hal_ctx, "input",
|
||||
&num_devices, &error);
|
||||
for (i = 0; i < num_devices; i++)
|
||||
device_added(info->hal_ctx, devices[i]);
|
||||
libhal_free_string_array(devices);
|
||||
|
||||
dbus_error_free(&error);
|
||||
|
||||
return;
|
||||
|
||||
out_ctx2:
|
||||
if (!libhal_ctx_shutdown(info->hal_ctx, &error))
|
||||
DebugF("[config/hal] couldn't shut down context?\n");
|
||||
out_ctx:
|
||||
libhal_ctx_free(info->hal_ctx);
|
||||
out_err:
|
||||
dbus_error_free(&error);
|
||||
|
||||
info->hal_ctx = NULL;
|
||||
info->system_bus = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static struct config_hal_info hal_info;
|
||||
static struct config_dbus_core_hook hook = {
|
||||
.connect = connect_hook,
|
||||
.disconnect = disconnect_hook,
|
||||
.data = &hal_info,
|
||||
};
|
||||
|
||||
int
|
||||
config_hal_init(void)
|
||||
{
|
||||
memset(&hal_info, 0, sizeof(hal_info));
|
||||
hal_info.system_bus = NULL;
|
||||
hal_info.hal_ctx = NULL;
|
||||
|
||||
if (!config_dbus_core_add_hook(&hook)) {
|
||||
ErrorF("[config/hal] failed to add D-Bus hook\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
config_hal_fini(void)
|
||||
{
|
||||
config_dbus_core_remove_hook(&hook);
|
||||
}
|
18
configure.ac
18
configure.ac
|
@ -520,6 +520,7 @@ AC_ARG_ENABLE(dbe, AS_HELP_STRING([--disable-dbe], [Build DBE extensi
|
|||
AC_ARG_ENABLE(xf86bigfont, AS_HELP_STRING([--disable-xf86bigfont], [Build XF86 Big Font extension (default: enabled)]), [XF86BIGFONT=$enableval], [XF86BIGFONT=yes])
|
||||
AC_ARG_ENABLE(dpms, AS_HELP_STRING([--disable-dpms], [Build DPMS extension (default: enabled)]), [DPMSExtension=$enableval], [DPMSExtension=yes])
|
||||
AC_ARG_ENABLE(config-dbus, AS_HELP_STRING([--disable-config-dbus], [Build D-BUS support (default: auto)]), [CONFIG_DBUS_API=$enableval], [CONFIG_DBUS_API=auto])
|
||||
AC_ARG_ENABLE(config-hal, AS_HELP_STRING([--disable-config-hal], [Build HAL support (default: auto)]), [CONFIG_HAL=$enableval], [CONFIG_HAL=auto])
|
||||
AC_ARG_ENABLE(xfree86-utils, AS_HELP_STRING([--enable-xfree86-utils], [Build xfree86 DDX utilities (default: enabled)]), [XF86UTILS=$enableval], [XF86UTILS=yes])
|
||||
|
||||
dnl DDXes.
|
||||
|
@ -637,14 +638,29 @@ if test "x$CONFIG_DBUS_API" = xyes; then
|
|||
fi
|
||||
|
||||
AC_DEFINE(CONFIG_DBUS_API, 1, [Use the D-Bus input configuration API])
|
||||
CONFIG_LIB='$(top_builddir)/config/libconfig.a'
|
||||
NEED_DBUS="yes"
|
||||
fi
|
||||
AM_CONDITIONAL(CONFIG_DBUS_API, [test "x$CONFIG_DBUS_API" = xyes])
|
||||
|
||||
PKG_CHECK_MODULES(HAL, hal, [HAVE_HAL=yes], [HAVE_HAL=no])
|
||||
if test "x$CONFIG_HAL" = xauto; then
|
||||
CONFIG_HAL="$HAVE_HAL"
|
||||
fi
|
||||
if test "x$CONFIG_HAL" = xyes; then
|
||||
if ! test "x$HAVE_HAL" = xyes; then
|
||||
AC_MSG_ERROR([HAL hotplug API requested, but HAL is not installed.])
|
||||
fi
|
||||
|
||||
AC_DEFINE(CONFIG_HAL, 1, [Use the HAL hotplug API])
|
||||
REQUIRED_LIBS="$REQUIRED_LIBS hal"
|
||||
NEED_DBUS="yes"
|
||||
fi
|
||||
AM_CONDITIONAL(CONFIG_HAL, [test "x$CONFIG_HAL" = xyes])
|
||||
|
||||
if test "x$NEED_DBUS" = xyes; then
|
||||
REQUIRED_LIBS="$REQUIRED_LIBS dbus-1"
|
||||
fi
|
||||
CONFIG_LIB='$(top_builddir)/config/libconfig.a'
|
||||
|
||||
AM_CONDITIONAL(XV, [test "x$XV" = xyes])
|
||||
if test "x$XV" = xyes; then
|
||||
|
|
|
@ -149,6 +149,7 @@ AddInputDevice(DeviceProc deviceProc, Bool autoStart)
|
|||
#ifdef XKB
|
||||
dev->xkb_interest = NULL;
|
||||
#endif
|
||||
dev->config_info = NULL;
|
||||
dev->nPrivates = 0;
|
||||
dev->devPrivates = NULL;
|
||||
dev->unwrapProc = NULL;
|
||||
|
|
|
@ -471,6 +471,9 @@
|
|||
/* Support the D-Bus hotplug API */
|
||||
#undef CONFIG_DBUS_API
|
||||
|
||||
/* Support HAL for hotplug */
|
||||
#undef CONFIG_HAL
|
||||
|
||||
/* Use only built-in fonts */
|
||||
#undef BUILTIN_FONTS
|
||||
|
||||
|
|
|
@ -326,6 +326,7 @@ typedef struct _DeviceIntRec {
|
|||
#else
|
||||
void *pad0;
|
||||
#endif
|
||||
char *config_info; /* used by the hotplug layer */
|
||||
DevUnion *devPrivates;
|
||||
int nPrivates;
|
||||
DeviceUnwrapProc unwrapProc;
|
||||
|
|
Loading…
Reference in New Issue