diff options
author | Sascha Hlusiak <saschahlusiak@arcor.de> | 2008-03-25 17:37:25 +0100 |
---|---|---|
committer | Sascha Hlusiak <saschahlusiak@arcor.de> | 2008-03-25 17:37:25 +0100 |
commit | 47eb658e802775021e3efec109f95431cca188ca (patch) | |
tree | b00594a30faea8f5d2ac6c8e9acac2fde860d88c /config | |
parent | f028e245a7932362656701c08fcfbfa8e8949077 (diff) |
Support to pass arbitrary options via HAL hotplugging
Parse "input.x11_options" and pass every key/name pair to the driver.
Remove check for input.capabilities, because that's part of the fdi files.
Thanks to Dustin Spicuzza <dustin@virtualroadside.com> for the patch.
Diffstat (limited to 'config')
-rw-r--r-- | config/hal.c | 194 | ||||
-rw-r--r-- | config/x11-input.fdi | 62 |
2 files changed, 171 insertions, 85 deletions
diff --git a/config/hal.c b/config/hal.c index 1575422c3..f15064646 100644 --- a/config/hal.c +++ b/config/hal.c @@ -38,9 +38,10 @@ #include "config-backends.h" #include "os.h" -#define TYPE_NONE 0 -#define TYPE_KEYS 1 -#define TYPE_POINTER 2 + +#define LIBHAL_PROP_KEY "input.x11_options." +#define LIBHAL_XKB_PROP_KEY "input.xkb." + struct config_hal_info { DBusConnection *system_bus; @@ -50,7 +51,8 @@ struct config_hal_info { static void remove_device(DeviceIntPtr dev) { - DebugF("[config/hal] removing device %s\n", dev->name); + /* this only gets called for devices that have already been added */ + LogMessage(X_INFO, "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. */ @@ -105,7 +107,7 @@ get_prop_string(LibHalContext *hal_ctx, const char *udi, const char *name) char *prop, *ret; prop = libhal_device_get_property_string(hal_ctx, udi, name, NULL); - DebugF("[config/hal] getting %s on %s returned %s\n", name, udi, prop); + LogMessageVerb(X_INFO, 10, "config/hal: getting %s on %s returned %s\n", name, udi, prop); if (prop) { ret = xstrdup(prop); libhal_free_string(prop); @@ -117,6 +119,9 @@ get_prop_string(LibHalContext *hal_ctx, const char *udi, const char *name) return ret; } +/* this function is no longer used... keep it here in case its needed in + * the future. */ +#if 0 static char * get_prop_string_array(LibHalContext *hal_ctx, const char *udi, const char *prop) { @@ -150,117 +155,146 @@ get_prop_string_array(LibHalContext *hal_ctx, const char *udi, const char *prop) return ret; } +#endif 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; + char *path = NULL, *driver = NULL, *name = NULL, *config_info = NULL; InputOption *options = NULL, *tmpo = NULL; DeviceIntPtr dev; DBusError error; - int type = TYPE_NONE; - int i; - + + LibHalPropertySet *set = NULL; + LibHalPropertySetIterator set_iter; + char *psi_key = NULL, *tmp_val, *tmp_key; + + 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 || - strcmp(props[i], "input.touchpad") == 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"); + if (!driver){ + /* verbose, don't tell the user unless they _want_ to see it */ + LogMessageVerb(X_INFO,7,"config/hal: no driver specified for device %s\n", udi); + goto unwind; + } + path = get_prop_string(hal_ctx, udi, "input.device"); - if (!driver || !path) { - DebugF("[config/hal] no driver or path specified for %s\n", udi); + if (!path) { + LogMessage(X_WARNING,"config/hal: no driver or path specified for %s\n", udi); goto unwind; } + name = get_prop_string(hal_ctx, udi, "info.product"); if (!name) name = xstrdup("(unnamed)"); - if (type & TYPE_KEYS) { - xkb_rules = get_prop_string(hal_ctx, udi, "input.xkb.rules"); - xkb_model = get_prop_string(hal_ctx, udi, "input.xkb.model"); - xkb_layout = get_prop_string(hal_ctx, udi, "input.xkb.layout"); - xkb_variant = get_prop_string(hal_ctx, udi, "input.xkb.variant"); - xkb_options = get_prop_string_array(hal_ctx, udi, "input.xkb.options"); - } - options = xcalloc(sizeof(*options), 1); + if (!options){ + LogMessage(X_ERROR, "config/hal: couldn't allocate space for input options!\n"); + goto unwind; + } + options->key = xstrdup("_source"); options->value = xstrdup("server/hal"); if (!options->key || !options->value) { - ErrorF("[config] couldn't allocate first key/value pair\n"); + LogMessage(X_ERROR, "config/hal: couldn't allocate first key/value pair\n"); goto unwind; } + /* most drivers use device.. not path. evdev uses both however, but the + * path version isn't documented apparently. support both for now. */ add_option(&options, "path", path); + add_option(&options, "device", path); + add_option(&options, "driver", driver); add_option(&options, "name", name); + config_info = xalloc(strlen(udi) + 5); /* "hal:" and NULL */ - if (!config_info) + if (!config_info) { + LogMessage(X_ERROR, "config/hal: couldn't allocate name\n"); goto unwind; + } sprintf(config_info, "hal:%s", udi); - if (xkb_rules) - add_option(&options, "xkb_rules", xkb_rules); - 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); - - DebugF("[config/hal] Adding device %s\n", name); + /* ok, grab options from hal.. iterate through all properties + * and lets see if any of them are options that we can add */ + set = libhal_device_get_all_properties(hal_ctx, udi, &error); + + if (!set) { + LogMessage(X_ERROR, "config/hal: couldn't get property list for %s: %s (%s)\n", + udi, error.name, error.message); + goto unwind; + } + + libhal_psi_init(&set_iter,set); + while (libhal_psi_has_more(&set_iter)) { + /* we are looking for supported keys.. extract and add to options */ + psi_key = libhal_psi_get_key(&set_iter); + + if (psi_key){ + + /* normal options first (input.x11_options.<propname>) */ + if (!strncasecmp(psi_key, LIBHAL_PROP_KEY, sizeof(LIBHAL_PROP_KEY)-1)){ + + /* only support strings for all values */ + tmp_val = get_prop_string(hal_ctx, udi, psi_key); + + if (tmp_val){ + add_option(&options, psi_key + sizeof(LIBHAL_PROP_KEY)-1, tmp_val); + xfree(tmp_val); + } + + /* evdev's XKB options... we should probably depreciate this usage */ + } else if (!strncasecmp(psi_key, LIBHAL_XKB_PROP_KEY, sizeof(LIBHAL_XKB_PROP_KEY)-1)){ + + /* only support strings for all values */ + tmp_val = get_prop_string(hal_ctx, udi, psi_key); + + if (tmp_val){ + /* add "xkb_" + NULL */ + tmp_key = xalloc(strlen(psi_key) - ( sizeof(LIBHAL_XKB_PROP_KEY) - 1) + 5); + + if (!tmp_key){ + LogMessage(X_ERROR, "config/hal: couldn't allocate memory for option %s\n", psi_key); + } else { + sprintf(tmp_key, "xkb_%s", psi_key + sizeof(LIBHAL_XKB_PROP_KEY)-1); + add_option(&options, tmp_key, tmp_val); + + xfree(tmp_key); + } + xfree(tmp_val); + } + } + } + + /* psi_key doesn't need to be freed */ + libhal_psi_next(&set_iter); + } + + /* this isn't an error, but how else do you output something that the user can see? */ + LogMessage(X_INFO, "config/hal: Adding input device %s\n", name); if (NewInputDeviceRequest(options, &dev) != Success) { - ErrorF("[config/hal] NewInputDeviceRequest failed\n"); + LogMessage(X_ERROR, "config/hal: NewInputDeviceRequest failed\n"); dev = NULL; goto unwind; } - for (; dev; dev = dev->next) + for (; dev; dev = dev->next){ + if (dev->config_info) + xfree(dev->config_info); dev->config_info = xstrdup(config_info); + } unwind: + if (set) + libhal_free_property_set(set); 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_variant) - xfree(xkb_variant); - if (xkb_options) - xfree(xkb_options); if (config_info) xfree(config_info); while (!dev && (tmpo = options)) { @@ -270,7 +304,6 @@ unwind: xfree(tmpo); } -out_error: dbus_error_free(&error); return; @@ -286,7 +319,7 @@ disconnect_hook(void *data) if (dbus_connection_get_is_connected(info->system_bus)) { dbus_error_init(&error); if (!libhal_ctx_shutdown(info->hal_ctx, &error)) - DebugF("[config/hal] couldn't shut down context: %s (%s)\n", + LogMessage(X_WARNING, "config/hal: disconnect_hook couldn't shut down context: %s (%s)\n", error.name, error.message); dbus_error_free(&error); } @@ -312,21 +345,21 @@ connect_hook(DBusConnection *connection, void *data) if (!info->hal_ctx) info->hal_ctx = libhal_ctx_new(); if (!info->hal_ctx) { - ErrorF("[config/hal] couldn't create HAL context\n"); + LogMessage(X_ERROR, "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"); + LogMessage(X_ERROR, "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", + LogMessage(X_ERROR, "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", + LogMessage(X_ERROR, "config/hal: couldn't watch all properties: %s (%s)\n", error.name, error.message); goto out_ctx2; } @@ -346,7 +379,7 @@ connect_hook(DBusConnection *connection, void *data) out_ctx2: if (!libhal_ctx_shutdown(info->hal_ctx, &error)) - DebugF("[config/hal] couldn't shut down context: %s (%s)\n", + LogMessage(X_WARNING, "config/hal: couldn't shut down context: %s (%s)\n", error.name, error.message); out_ctx: libhal_ctx_free(info->hal_ctx); @@ -374,10 +407,13 @@ config_hal_init(void) hal_info.hal_ctx = NULL; if (!config_dbus_core_add_hook(&hook)) { - ErrorF("[config/hal] failed to add D-Bus hook\n"); + LogMessage(X_ERROR, "config/hal: failed to add D-Bus hook\n"); return 0; } + /* verbose message */ + LogMessageVerb(X_INFO,7,"config/hal: initialized"); + return 1; } diff --git a/config/x11-input.fdi b/config/x11-input.fdi index c390706fb..f2e2d50ab 100644 --- a/config/x11-input.fdi +++ b/config/x11-input.fdi @@ -1,7 +1,57 @@ <?xml version="1.0" encoding="UTF-8"?> <deviceinfo version="0.2"> <device> - <!-- FIXME: Support tablets too. --> + + <!-- The way this works: + + Match against some input device (see the HAL specification for more + information), and then merge in keys, which you can use to specify + the configuration similar to the way you would in xorg.conf. You will + need to restart HAL after making changes. If you are having issues, + starting X with the -logverbose 7 flag may yield useful information. + + Keys Supported: + + Key "input.x11_driver" (string) + This specifies the driver to use. You MUST specify this option, + or a driver will not be loaded and the rest will be ignored by + Xorg + + Key "input.x11_options.<option name>" (string) + This allows you to specify arbitrary options to pass to the driver. + Anything you would normally specify in xorg.conf goes here. So, for + option "Mode" in xorg.conf, you would specify the key name of + "input.x11_options.Mode". + + Do not specify "input.x11_options.Device" since "input.device" + will be used automatically. + + Legacy Keys + "input.xkb.rules" + "input.xkb.model" + "input.xkb.layout" + "input.xkb.variant" + "input.xkb.options" + + These keys are deprecated. Use these instead: + "input.x11_options.XkbRules" + "input.x11_options.XkbModel" + "input.x11_options.XkbLayout" + "input.x11_options.XkbVariant" + "input.x11_options.XkbOptions" + + See the evdev documentation for more information. + + You will probably want to add the following option to the ServerFlags of + your xorg.conf: + + Option "AllowEmptyInput" "True" + + FIXME: Support tablets too. + TODO: I think its fixed, can't test + + --> + <match key="info.capabilities" contains="input.mouse"> <merge key="input.x11_driver" type="string">mouse</merge> <match key="/org/freedesktop/Hal/devices/computer:system.kernel.name" @@ -11,21 +61,21 @@ </match> <match key="info.capabilities" contains="input.keys"> - <merge key="input.xkb.rules" type="string">base</merge> + <merge key="input.x11_options.XkbRules" type="string">base</merge> <!-- If we're using Linux, we use evdev by default (falling back to keyboard otherwise). --> <merge key="input.x11_driver" type="string">keyboard</merge> - <merge key="input.xkb.model" type="string">pc105</merge> + <merge key="input.x11_options.XkbModel" type="string">pc105</merge> <match key="/org/freedesktop/Hal/devices/computer:system.kernel.name" string="Linux"> <merge key="input.x11_driver" type="string">evdev</merge> - <merge key="input.xkb.model" type="string">evdev</merge> + <merge key="input.x11_options.XkbModel" type="string">evdev</merge> </match> - <merge key="input.xkb.layout" type="string">us</merge> + <merge key="input.x11_options.XkbLayout" type="string">us</merge> - <merge key="input.xkb.variant" type="string" /> + <merge key="input.x11_options.XkbVariant" type="string" /> </match> </device> </deviceinfo> |