hal.c revision 35c4bbdf
105b261ecSmrg/* 205b261ecSmrg * Copyright © 2007 Daniel Stone 34642e01fSmrg * Copyright © 2007 Red Hat, Inc. 405b261ecSmrg * 505b261ecSmrg * Permission is hereby granted, free of charge, to any person obtaining a 605b261ecSmrg * copy of this software and associated documentation files (the "Software"), 705b261ecSmrg * to deal in the Software without restriction, including without limitation 805b261ecSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 905b261ecSmrg * and/or sell copies of the Software, and to permit persons to whom the 1005b261ecSmrg * Software is furnished to do so, subject to the following conditions: 1105b261ecSmrg * 1205b261ecSmrg * The above copyright notice and this permission notice (including the next 1305b261ecSmrg * paragraph) shall be included in all copies or substantial portions of the 1405b261ecSmrg * Software. 1505b261ecSmrg * 1605b261ecSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1705b261ecSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1805b261ecSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1905b261ecSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2005b261ecSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2105b261ecSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2205b261ecSmrg * DEALINGS IN THE SOFTWARE. 2305b261ecSmrg * 2405b261ecSmrg * Author: Daniel Stone <daniel@fooishbar.org> 2505b261ecSmrg */ 2605b261ecSmrg 2705b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 2805b261ecSmrg#include <dix-config.h> 2905b261ecSmrg#endif 3005b261ecSmrg 3105b261ecSmrg#include <dbus/dbus.h> 3205b261ecSmrg#include <hal/libhal.h> 3305b261ecSmrg#include <string.h> 3405b261ecSmrg#include <sys/select.h> 3505b261ecSmrg 3635c4bbdfSmrg#include "dbus-core.h" 3705b261ecSmrg#include "input.h" 3805b261ecSmrg#include "inputstr.h" 3905b261ecSmrg#include "hotplug.h" 4005b261ecSmrg#include "config-backends.h" 4105b261ecSmrg#include "os.h" 4205b261ecSmrg 434642e01fSmrg#define LIBHAL_PROP_KEY "input.x11_options." 444642e01fSmrg#define LIBHAL_XKB_PROP_KEY "input.xkb." 454642e01fSmrg 4605b261ecSmrgstruct config_hal_info { 4705b261ecSmrg DBusConnection *system_bus; 4805b261ecSmrg LibHalContext *hal_ctx; 4905b261ecSmrg}; 5005b261ecSmrg 514642e01fSmrg/* Used for special handling of xkb options. */ 524642e01fSmrgstruct xkb_options { 5335c4bbdfSmrg char *layout; 5435c4bbdfSmrg char *model; 5535c4bbdfSmrg char *rules; 5635c4bbdfSmrg char *variant; 5735c4bbdfSmrg char *options; 584642e01fSmrg}; 594642e01fSmrg 6005b261ecSmrgstatic void 6135c4bbdfSmrgdevice_removed(LibHalContext * ctx, const char *udi) 6205b261ecSmrg{ 6305b261ecSmrg char *value; 6405b261ecSmrg 6535c4bbdfSmrg if (asprintf(&value, "hal:%s", udi) == -1) 6605b261ecSmrg return; 6705b261ecSmrg 686747b715Smrg remove_devices("hal", value); 6905b261ecSmrg 706747b715Smrg free(value); 7105b261ecSmrg} 7205b261ecSmrg 7305b261ecSmrgstatic char * 7435c4bbdfSmrgget_prop_string(LibHalContext * hal_ctx, const char *udi, const char *name) 7505b261ecSmrg{ 7605b261ecSmrg char *prop, *ret; 7705b261ecSmrg 7805b261ecSmrg prop = libhal_device_get_property_string(hal_ctx, udi, name, NULL); 7935c4bbdfSmrg LogMessageVerb(X_INFO, 10, "config/hal: getting %s on %s returned %s\n", 8035c4bbdfSmrg name, udi, prop ? prop : "(null)"); 8105b261ecSmrg if (prop) { 826747b715Smrg ret = strdup(prop); 8305b261ecSmrg libhal_free_string(prop); 8405b261ecSmrg } 8505b261ecSmrg else { 8605b261ecSmrg return NULL; 8705b261ecSmrg } 8805b261ecSmrg 8905b261ecSmrg return ret; 9005b261ecSmrg} 9105b261ecSmrg 9205b261ecSmrgstatic char * 9335c4bbdfSmrgget_prop_string_array(LibHalContext * hal_ctx, const char *udi, 9435c4bbdfSmrg const char *prop) 9505b261ecSmrg{ 9605b261ecSmrg char **props, *ret, *str; 9705b261ecSmrg int i, len = 0; 9805b261ecSmrg 9905b261ecSmrg props = libhal_device_get_property_strlist(hal_ctx, udi, prop, NULL); 10005b261ecSmrg if (props) { 10105b261ecSmrg for (i = 0; props[i]; i++) 10205b261ecSmrg len += strlen(props[i]); 10305b261ecSmrg 10435c4bbdfSmrg ret = calloc(sizeof(char), len + i); /* i - 1 commas, 1 NULL */ 10505b261ecSmrg if (!ret) { 10605b261ecSmrg libhal_free_string_array(props); 10705b261ecSmrg return NULL; 10805b261ecSmrg } 10905b261ecSmrg 11005b261ecSmrg str = ret; 11105b261ecSmrg for (i = 0; props[i]; i++) { 11205b261ecSmrg strcpy(str, props[i]); 11305b261ecSmrg str += strlen(props[i]); 11405b261ecSmrg *str++ = ','; 11505b261ecSmrg } 11635c4bbdfSmrg *(str - 1) = '\0'; 11705b261ecSmrg 11805b261ecSmrg libhal_free_string_array(props); 11905b261ecSmrg } 12005b261ecSmrg else { 12105b261ecSmrg return NULL; 12205b261ecSmrg } 12305b261ecSmrg 12405b261ecSmrg return ret; 12505b261ecSmrg} 12605b261ecSmrg 12705b261ecSmrgstatic void 12835c4bbdfSmrgdevice_added(LibHalContext * hal_ctx, const char *udi) 12905b261ecSmrg{ 1304642e01fSmrg char *path = NULL, *driver = NULL, *name = NULL, *config_info = NULL; 1316747b715Smrg char *hal_tags, *parent; 13235c4bbdfSmrg InputOption *input_options = NULL; 13335c4bbdfSmrg InputAttributes attrs = { 0 }; 1344642e01fSmrg DeviceIntPtr dev = NULL; 13505b261ecSmrg DBusError error; 13635c4bbdfSmrg struct xkb_options xkb_opts = { 0 }; 1374642e01fSmrg int rc; 13805b261ecSmrg 1394642e01fSmrg LibHalPropertySet *set = NULL; 14035c4bbdfSmrg LibHalPropertySetIterator set_iter; 1414642e01fSmrg char *psi_key = NULL, *tmp_val; 14205b261ecSmrg 1434642e01fSmrg dbus_error_init(&error); 14405b261ecSmrg 14505b261ecSmrg driver = get_prop_string(hal_ctx, udi, "input.x11_driver"); 14635c4bbdfSmrg if (!driver) { 1474642e01fSmrg /* verbose, don't tell the user unless they _want_ to see it */ 14835c4bbdfSmrg LogMessageVerb(X_INFO, 7, 14935c4bbdfSmrg "config/hal: no driver specified for device %s\n", udi); 1504642e01fSmrg goto unwind; 1514642e01fSmrg } 1524642e01fSmrg 15305b261ecSmrg path = get_prop_string(hal_ctx, udi, "input.device"); 1544642e01fSmrg if (!path) { 15535c4bbdfSmrg LogMessage(X_WARNING, 15635c4bbdfSmrg "config/hal: no driver or path specified for %s\n", udi); 15705b261ecSmrg goto unwind; 15805b261ecSmrg } 1596747b715Smrg attrs.device = strdup(path); 1604642e01fSmrg 16105b261ecSmrg name = get_prop_string(hal_ctx, udi, "info.product"); 16205b261ecSmrg if (!name) 1636747b715Smrg name = strdup("(unnamed)"); 1646747b715Smrg else 1656747b715Smrg attrs.product = strdup(name); 1666747b715Smrg 1676747b715Smrg attrs.vendor = get_prop_string(hal_ctx, udi, "info.vendor"); 1686747b715Smrg hal_tags = get_prop_string(hal_ctx, udi, "input.tags"); 1696747b715Smrg attrs.tags = xstrtokenize(hal_tags, ","); 1706747b715Smrg free(hal_tags); 1716747b715Smrg 1726747b715Smrg if (libhal_device_query_capability(hal_ctx, udi, "input.keys", NULL)) 1736747b715Smrg attrs.flags |= ATTR_KEYBOARD; 1746747b715Smrg if (libhal_device_query_capability(hal_ctx, udi, "input.mouse", NULL)) 1756747b715Smrg attrs.flags |= ATTR_POINTER; 1766747b715Smrg if (libhal_device_query_capability(hal_ctx, udi, "input.joystick", NULL)) 1776747b715Smrg attrs.flags |= ATTR_JOYSTICK; 1786747b715Smrg if (libhal_device_query_capability(hal_ctx, udi, "input.tablet", NULL)) 1796747b715Smrg attrs.flags |= ATTR_TABLET; 1806747b715Smrg if (libhal_device_query_capability(hal_ctx, udi, "input.touchpad", NULL)) 1816747b715Smrg attrs.flags |= ATTR_TOUCHPAD; 1826747b715Smrg if (libhal_device_query_capability(hal_ctx, udi, "input.touchscreen", NULL)) 1836747b715Smrg attrs.flags |= ATTR_TOUCHSCREEN; 1846747b715Smrg 1856747b715Smrg parent = get_prop_string(hal_ctx, udi, "info.parent"); 1866747b715Smrg if (parent) { 1876747b715Smrg int usb_vendor, usb_product; 18835c4bbdfSmrg char *old_parent; 1896747b715Smrg 1906747b715Smrg /* construct USB ID in lowercase - "0000:ffff" */ 1916747b715Smrg usb_vendor = libhal_device_get_property_int(hal_ctx, parent, 1926747b715Smrg "usb.vendor_id", NULL); 1936747b715Smrg LogMessageVerb(X_INFO, 10, 1946747b715Smrg "config/hal: getting usb.vendor_id on %s " 1956747b715Smrg "returned %04x\n", parent, usb_vendor); 1966747b715Smrg usb_product = libhal_device_get_property_int(hal_ctx, parent, 1976747b715Smrg "usb.product_id", NULL); 1986747b715Smrg LogMessageVerb(X_INFO, 10, 1996747b715Smrg "config/hal: getting usb.product_id on %s " 2006747b715Smrg "returned %04x\n", parent, usb_product); 2016747b715Smrg if (usb_vendor && usb_product) 2029ace9065Smrg if (asprintf(&attrs.usb_id, "%04x:%04x", usb_vendor, usb_product) 20335c4bbdfSmrg == -1) 20435c4bbdfSmrg attrs.usb_id = NULL; 2056747b715Smrg 20635c4bbdfSmrg attrs.pnp_id = get_prop_string(hal_ctx, parent, "pnp.id"); 20735c4bbdfSmrg old_parent = parent; 20805b261ecSmrg 20935c4bbdfSmrg while (!attrs.pnp_id && 21035c4bbdfSmrg (parent = get_prop_string(hal_ctx, parent, "info.parent"))) { 21135c4bbdfSmrg attrs.pnp_id = get_prop_string(hal_ctx, parent, "pnp.id"); 21235c4bbdfSmrg 21335c4bbdfSmrg free(old_parent); 21435c4bbdfSmrg old_parent = parent; 21535c4bbdfSmrg } 21635c4bbdfSmrg 21735c4bbdfSmrg free(old_parent); 21805b261ecSmrg } 21905b261ecSmrg 22035c4bbdfSmrg input_options = input_option_new(NULL, "_source", "server/hal"); 22135c4bbdfSmrg if (!input_options) { 22235c4bbdfSmrg LogMessage(X_ERROR, 22335c4bbdfSmrg "config/hal: couldn't allocate first key/value pair\n"); 22405b261ecSmrg goto unwind; 22505b261ecSmrg } 22605b261ecSmrg 2274642e01fSmrg /* most drivers use device.. not path. evdev uses both however, but the 2284642e01fSmrg * path version isn't documented apparently. support both for now. */ 22935c4bbdfSmrg input_options = input_option_new(input_options, "path", path); 23035c4bbdfSmrg input_options = input_option_new(input_options, "device", path); 2314642e01fSmrg 23235c4bbdfSmrg input_options = input_option_new(input_options, "driver", driver); 23335c4bbdfSmrg input_options = input_option_new(input_options, "name", name); 2344642e01fSmrg 23535c4bbdfSmrg if (asprintf(&config_info, "hal:%s", udi) == -1) { 2369ace9065Smrg config_info = NULL; 2374642e01fSmrg LogMessage(X_ERROR, "config/hal: couldn't allocate name\n"); 23805b261ecSmrg goto unwind; 2394642e01fSmrg } 24005b261ecSmrg 2414642e01fSmrg /* Check for duplicate devices */ 24235c4bbdfSmrg if (device_is_duplicate(config_info)) { 24335c4bbdfSmrg LogMessage(X_WARNING, 24435c4bbdfSmrg "config/hal: device %s already added. Ignoring.\n", name); 2454642e01fSmrg goto unwind; 2464642e01fSmrg } 2474642e01fSmrg 2484642e01fSmrg /* ok, grab options from hal.. iterate through all properties 24935c4bbdfSmrg * and lets see if any of them are options that we can add */ 2504642e01fSmrg set = libhal_device_get_all_properties(hal_ctx, udi, &error); 2514642e01fSmrg 2524642e01fSmrg if (!set) { 25335c4bbdfSmrg LogMessage(X_ERROR, 25435c4bbdfSmrg "config/hal: couldn't get property list for %s: %s (%s)\n", 25535c4bbdfSmrg udi, error.name, error.message); 2564642e01fSmrg goto unwind; 2574642e01fSmrg } 2584642e01fSmrg 25935c4bbdfSmrg libhal_psi_init(&set_iter, set); 2604642e01fSmrg while (libhal_psi_has_more(&set_iter)) { 2614642e01fSmrg /* we are looking for supported keys.. extract and add to options */ 2624642e01fSmrg psi_key = libhal_psi_get_key(&set_iter); 2634642e01fSmrg 26435c4bbdfSmrg if (psi_key) { 2654642e01fSmrg 2664642e01fSmrg /* normal options first (input.x11_options.<propname>) */ 26735c4bbdfSmrg if (!strncasecmp 26835c4bbdfSmrg (psi_key, LIBHAL_PROP_KEY, sizeof(LIBHAL_PROP_KEY) - 1)) { 26935c4bbdfSmrg char *tmp; 2704642e01fSmrg 2714642e01fSmrg /* only support strings for all values */ 2724642e01fSmrg tmp_val = get_prop_string(hal_ctx, udi, psi_key); 2734642e01fSmrg 27435c4bbdfSmrg if (tmp_val) { 2754642e01fSmrg 2764642e01fSmrg /* xkb needs special handling. HAL specs include 2774642e01fSmrg * input.xkb.xyz options, but the x11-input.fdi specifies 2784642e01fSmrg * input.x11_options.Xkbxyz options. By default, we use 2794642e01fSmrg * the former, unless the specific X11 ones are specified. 2804642e01fSmrg * Since we can't predict the order in which the keys 2814642e01fSmrg * arrive, we need to store them. 2824642e01fSmrg */ 28335c4bbdfSmrg if ((tmp = strcasestr(psi_key, "xkb")) && strlen(tmp) >= 4) { 28435c4bbdfSmrg if (!strcasecmp(&tmp[3], "layout")) { 2856747b715Smrg free(xkb_opts.layout); 2864642e01fSmrg xkb_opts.layout = strdup(tmp_val); 28735c4bbdfSmrg } 28835c4bbdfSmrg else if (!strcasecmp(&tmp[3], "model")) { 2896747b715Smrg free(xkb_opts.model); 2904642e01fSmrg xkb_opts.model = strdup(tmp_val); 29135c4bbdfSmrg } 29235c4bbdfSmrg else if (!strcasecmp(&tmp[3], "rules")) { 2936747b715Smrg free(xkb_opts.rules); 2944642e01fSmrg xkb_opts.rules = strdup(tmp_val); 29535c4bbdfSmrg } 29635c4bbdfSmrg else if (!strcasecmp(&tmp[3], "variant")) { 2976747b715Smrg free(xkb_opts.variant); 2984642e01fSmrg xkb_opts.variant = strdup(tmp_val); 29935c4bbdfSmrg } 30035c4bbdfSmrg else if (!strcasecmp(&tmp[3], "options")) { 3016747b715Smrg free(xkb_opts.options); 3024642e01fSmrg xkb_opts.options = strdup(tmp_val); 3034642e01fSmrg } 30435c4bbdfSmrg } 30535c4bbdfSmrg else { 3064642e01fSmrg /* all others */ 30735c4bbdfSmrg input_options = 30835c4bbdfSmrg input_option_new(input_options, 30935c4bbdfSmrg psi_key + sizeof(LIBHAL_PROP_KEY) - 31035c4bbdfSmrg 1, tmp_val); 3116747b715Smrg free(tmp_val); 3124642e01fSmrg } 31335c4bbdfSmrg } 31435c4bbdfSmrg else { 3154642e01fSmrg /* server 1.4 had xkb_options as strlist. */ 3164642e01fSmrg if ((tmp = strcasestr(psi_key, "xkb")) && 3174642e01fSmrg (strlen(tmp) >= 4) && 3184642e01fSmrg (!strcasecmp(&tmp[3], "options")) && 31935c4bbdfSmrg (tmp_val = 32035c4bbdfSmrg get_prop_string_array(hal_ctx, udi, psi_key))) { 3216747b715Smrg free(xkb_opts.options); 3224642e01fSmrg xkb_opts.options = strdup(tmp_val); 3234642e01fSmrg } 3244642e01fSmrg } 32535c4bbdfSmrg } 32635c4bbdfSmrg else if (!strncasecmp 32735c4bbdfSmrg (psi_key, LIBHAL_XKB_PROP_KEY, 32835c4bbdfSmrg sizeof(LIBHAL_XKB_PROP_KEY) - 1)) { 32935c4bbdfSmrg char *tmp; 3304642e01fSmrg 3314642e01fSmrg /* only support strings for all values */ 3324642e01fSmrg tmp_val = get_prop_string(hal_ctx, udi, psi_key); 3334642e01fSmrg 3344642e01fSmrg if (tmp_val && strlen(psi_key) >= sizeof(LIBHAL_XKB_PROP_KEY)) { 3354642e01fSmrg 3364642e01fSmrg tmp = &psi_key[sizeof(LIBHAL_XKB_PROP_KEY) - 1]; 3374642e01fSmrg 33835c4bbdfSmrg if (!strcasecmp(tmp, "layout")) { 3394642e01fSmrg if (!xkb_opts.layout) 3404642e01fSmrg xkb_opts.layout = strdup(tmp_val); 34135c4bbdfSmrg } 34235c4bbdfSmrg else if (!strcasecmp(tmp, "rules")) { 3434642e01fSmrg if (!xkb_opts.rules) 3444642e01fSmrg xkb_opts.rules = strdup(tmp_val); 34535c4bbdfSmrg } 34635c4bbdfSmrg else if (!strcasecmp(tmp, "variant")) { 3474642e01fSmrg if (!xkb_opts.variant) 3484642e01fSmrg xkb_opts.variant = strdup(tmp_val); 34935c4bbdfSmrg } 35035c4bbdfSmrg else if (!strcasecmp(tmp, "model")) { 3514642e01fSmrg if (!xkb_opts.model) 3524642e01fSmrg xkb_opts.model = strdup(tmp_val); 35335c4bbdfSmrg } 35435c4bbdfSmrg else if (!strcasecmp(tmp, "options")) { 3554642e01fSmrg if (!xkb_opts.options) 3564642e01fSmrg xkb_opts.options = strdup(tmp_val); 3574642e01fSmrg } 3586747b715Smrg free(tmp_val); 35935c4bbdfSmrg } 36035c4bbdfSmrg else { 3614642e01fSmrg /* server 1.4 had xkb options as strlist */ 3624642e01fSmrg tmp_val = get_prop_string_array(hal_ctx, udi, psi_key); 36335c4bbdfSmrg if (tmp_val && 36435c4bbdfSmrg strlen(psi_key) >= sizeof(LIBHAL_XKB_PROP_KEY)) { 3654642e01fSmrg tmp = &psi_key[sizeof(LIBHAL_XKB_PROP_KEY) - 1]; 3664642e01fSmrg if (!strcasecmp(tmp, ".options") && (!xkb_opts.options)) 3674642e01fSmrg xkb_opts.options = strdup(tmp_val); 3684642e01fSmrg } 369475c125cSmrg free(tmp_val); 3704642e01fSmrg } 3714642e01fSmrg } 3724642e01fSmrg } 3734642e01fSmrg 3744642e01fSmrg /* psi_key doesn't need to be freed */ 3754642e01fSmrg libhal_psi_next(&set_iter); 3764642e01fSmrg } 3774642e01fSmrg 3784642e01fSmrg /* Now add xkb options */ 3794642e01fSmrg if (xkb_opts.layout) 38035c4bbdfSmrg input_options = 38135c4bbdfSmrg input_option_new(input_options, "xkb_layout", xkb_opts.layout); 3824642e01fSmrg if (xkb_opts.rules) 38335c4bbdfSmrg input_options = 38435c4bbdfSmrg input_option_new(input_options, "xkb_rules", xkb_opts.rules); 3854642e01fSmrg if (xkb_opts.variant) 38635c4bbdfSmrg input_options = 38735c4bbdfSmrg input_option_new(input_options, "xkb_variant", xkb_opts.variant); 3884642e01fSmrg if (xkb_opts.model) 38935c4bbdfSmrg input_options = 39035c4bbdfSmrg input_option_new(input_options, "xkb_model", xkb_opts.model); 3914642e01fSmrg if (xkb_opts.options) 39235c4bbdfSmrg input_options = 39335c4bbdfSmrg input_option_new(input_options, "xkb_options", xkb_opts.options); 39435c4bbdfSmrg input_options = input_option_new(input_options, "config_info", config_info); 3954642e01fSmrg 3964642e01fSmrg /* this isn't an error, but how else do you output something that the user can see? */ 3974642e01fSmrg LogMessage(X_INFO, "config/hal: Adding input device %s\n", name); 39835c4bbdfSmrg if ((rc = NewInputDeviceRequest(input_options, &attrs, &dev)) != Success) { 39935c4bbdfSmrg LogMessage(X_ERROR, "config/hal: NewInputDeviceRequest failed (%d)\n", 40035c4bbdfSmrg rc); 40105b261ecSmrg dev = NULL; 40205b261ecSmrg goto unwind; 40305b261ecSmrg } 40405b261ecSmrg 40535c4bbdfSmrg unwind: 4064642e01fSmrg if (set) 4074642e01fSmrg libhal_free_property_set(set); 4086747b715Smrg free(path); 4096747b715Smrg free(driver); 4106747b715Smrg free(name); 4116747b715Smrg free(config_info); 41235c4bbdfSmrg input_option_free_list(&input_options); 41305b261ecSmrg 4146747b715Smrg free(attrs.product); 4156747b715Smrg free(attrs.vendor); 4166747b715Smrg free(attrs.device); 4176747b715Smrg free(attrs.pnp_id); 4186747b715Smrg free(attrs.usb_id); 4196747b715Smrg if (attrs.tags) { 4206747b715Smrg char **tag = attrs.tags; 42135c4bbdfSmrg 4226747b715Smrg while (*tag) { 4236747b715Smrg free(*tag); 4246747b715Smrg tag++; 4256747b715Smrg } 4266747b715Smrg free(attrs.tags); 4276747b715Smrg } 4286747b715Smrg 4296747b715Smrg free(xkb_opts.layout); 4306747b715Smrg free(xkb_opts.rules); 4316747b715Smrg free(xkb_opts.model); 4326747b715Smrg free(xkb_opts.variant); 4336747b715Smrg free(xkb_opts.options); 4344642e01fSmrg 43505b261ecSmrg dbus_error_free(&error); 43605b261ecSmrg 43705b261ecSmrg return; 43805b261ecSmrg} 43905b261ecSmrg 44005b261ecSmrgstatic void 44105b261ecSmrgdisconnect_hook(void *data) 44205b261ecSmrg{ 44305b261ecSmrg DBusError error; 44405b261ecSmrg struct config_hal_info *info = data; 44505b261ecSmrg 44605b261ecSmrg if (info->hal_ctx) { 4474642e01fSmrg if (dbus_connection_get_is_connected(info->system_bus)) { 4484642e01fSmrg dbus_error_init(&error); 4494642e01fSmrg if (!libhal_ctx_shutdown(info->hal_ctx, &error)) 45035c4bbdfSmrg LogMessage(X_WARNING, 45135c4bbdfSmrg "config/hal: disconnect_hook couldn't shut down context: %s (%s)\n", 45235c4bbdfSmrg error.name, error.message); 4534642e01fSmrg dbus_error_free(&error); 4544642e01fSmrg } 45505b261ecSmrg libhal_ctx_free(info->hal_ctx); 45605b261ecSmrg } 45705b261ecSmrg 45805b261ecSmrg info->hal_ctx = NULL; 45905b261ecSmrg info->system_bus = NULL; 46005b261ecSmrg} 46105b261ecSmrg 4624642e01fSmrgstatic BOOL 46335c4bbdfSmrgconnect_and_register(DBusConnection * connection, struct config_hal_info *info) 46405b261ecSmrg{ 46505b261ecSmrg DBusError error; 46605b261ecSmrg char **devices; 46705b261ecSmrg int num_devices, i; 46805b261ecSmrg 469b86d567bSmrg if (info->hal_ctx) 47035c4bbdfSmrg return TRUE; /* already registered, pretend we did something */ 471b86d567bSmrg 47205b261ecSmrg info->system_bus = connection; 47305b261ecSmrg 47405b261ecSmrg dbus_error_init(&error); 47505b261ecSmrg 4764642e01fSmrg info->hal_ctx = libhal_ctx_new(); 47705b261ecSmrg if (!info->hal_ctx) { 4784642e01fSmrg LogMessage(X_ERROR, "config/hal: couldn't create HAL context\n"); 47905b261ecSmrg goto out_err; 48005b261ecSmrg } 48105b261ecSmrg 48205b261ecSmrg if (!libhal_ctx_set_dbus_connection(info->hal_ctx, info->system_bus)) { 48335c4bbdfSmrg LogMessage(X_ERROR, 48435c4bbdfSmrg "config/hal: couldn't associate HAL context with bus\n"); 485b1d344b3Smrg goto out_err; 48605b261ecSmrg } 48705b261ecSmrg if (!libhal_ctx_init(info->hal_ctx, &error)) { 48835c4bbdfSmrg LogMessage(X_ERROR, 48935c4bbdfSmrg "config/hal: couldn't initialise context: %s (%s)\n", 49035c4bbdfSmrg error.name ? error.name : "unknown error", 49135c4bbdfSmrg error.message ? error.message : "null"); 492b1d344b3Smrg goto out_err; 49305b261ecSmrg } 49405b261ecSmrg if (!libhal_device_property_watch_all(info->hal_ctx, &error)) { 49535c4bbdfSmrg LogMessage(X_ERROR, 49635c4bbdfSmrg "config/hal: couldn't watch all properties: %s (%s)\n", 49735c4bbdfSmrg error.name ? error.name : "unknown error", 49835c4bbdfSmrg error.message ? error.message : "null"); 499b86d567bSmrg goto out_ctx; 50005b261ecSmrg } 50105b261ecSmrg libhal_ctx_set_device_added(info->hal_ctx, device_added); 50205b261ecSmrg libhal_ctx_set_device_removed(info->hal_ctx, device_removed); 50305b261ecSmrg 50405b261ecSmrg devices = libhal_find_device_by_capability(info->hal_ctx, "input", 50505b261ecSmrg &num_devices, &error); 50605b261ecSmrg /* FIXME: Get default devices if error is set. */ 507b86d567bSmrg if (dbus_error_is_set(&error)) { 508b86d567bSmrg LogMessage(X_ERROR, "config/hal: couldn't find input device: %s (%s)\n", 50935c4bbdfSmrg error.name ? error.name : "unknown error", 51035c4bbdfSmrg error.message ? error.message : "null"); 511b86d567bSmrg goto out_ctx; 512b86d567bSmrg } 51305b261ecSmrg for (i = 0; i < num_devices; i++) 51405b261ecSmrg device_added(info->hal_ctx, devices[i]); 51505b261ecSmrg libhal_free_string_array(devices); 51605b261ecSmrg 51705b261ecSmrg dbus_error_free(&error); 51805b261ecSmrg 5194642e01fSmrg return TRUE; 52005b261ecSmrg 52135c4bbdfSmrg out_ctx: 522b86d567bSmrg dbus_error_free(&error); 523b86d567bSmrg 524b1d344b3Smrg if (!libhal_ctx_shutdown(info->hal_ctx, &error)) { 52535c4bbdfSmrg LogMessage(X_WARNING, 52635c4bbdfSmrg "config/hal: couldn't shut down context: %s (%s)\n", 52735c4bbdfSmrg error.name ? error.name : "unknown error", 52835c4bbdfSmrg error.message ? error.message : "null"); 529b1d344b3Smrg dbus_error_free(&error); 530b86d567bSmrg } 531b86d567bSmrg 53235c4bbdfSmrg out_err: 53305b261ecSmrg dbus_error_free(&error); 53405b261ecSmrg 535b1d344b3Smrg if (info->hal_ctx) { 536b1d344b3Smrg libhal_ctx_free(info->hal_ctx); 537b1d344b3Smrg } 538b1d344b3Smrg 53905b261ecSmrg info->hal_ctx = NULL; 54005b261ecSmrg info->system_bus = NULL; 54105b261ecSmrg 5424642e01fSmrg return FALSE; 5434642e01fSmrg} 5444642e01fSmrg 5454642e01fSmrg/** 5464642e01fSmrg * Handle NewOwnerChanged signals to deal with HAL startup at X server runtime. 5474642e01fSmrg * 5484642e01fSmrg * NewOwnerChanged is send once when HAL shuts down, and once again when it 5494642e01fSmrg * comes back up. Message has three arguments, first is the name 5504642e01fSmrg * (org.freedesktop.Hal), the second one is the old owner, third one is new 5514642e01fSmrg * owner. 5524642e01fSmrg */ 5534642e01fSmrgstatic DBusHandlerResult 55435c4bbdfSmrgownerchanged_handler(DBusConnection * connection, DBusMessage * message, 55535c4bbdfSmrg void *data) 5564642e01fSmrg{ 5574642e01fSmrg int ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 5584642e01fSmrg 5594642e01fSmrg if (dbus_message_is_signal(message, 56035c4bbdfSmrg "org.freedesktop.DBus", "NameOwnerChanged")) { 5614642e01fSmrg DBusError error; 5624642e01fSmrg char *name, *old_owner, *new_owner; 5634642e01fSmrg 5644642e01fSmrg dbus_error_init(&error); 5654642e01fSmrg dbus_message_get_args(message, &error, 5664642e01fSmrg DBUS_TYPE_STRING, &name, 5674642e01fSmrg DBUS_TYPE_STRING, &old_owner, 56835c4bbdfSmrg DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID); 5694642e01fSmrg 5704642e01fSmrg if (dbus_error_is_set(&error)) { 57135c4bbdfSmrg ErrorF 57235c4bbdfSmrg ("[config/hal] failed to get NameOwnerChanged args: %s (%s)\n", 57335c4bbdfSmrg error.name, error.message); 57435c4bbdfSmrg } 57535c4bbdfSmrg else if (name && strcmp(name, "org.freedesktop.Hal") == 0) { 5764642e01fSmrg 5774642e01fSmrg if (!old_owner || !strlen(old_owner)) { 5784642e01fSmrg DebugF("[config/hal] HAL startup detected.\n"); 57935c4bbdfSmrg if (connect_and_register 58035c4bbdfSmrg (connection, (struct config_hal_info *) data)) 5814642e01fSmrg dbus_connection_unregister_object_path(connection, 58235c4bbdfSmrg "/org/freedesktop/DBus"); 5834642e01fSmrg else 5844642e01fSmrg ErrorF("[config/hal] Failed to connect to HAL bus.\n"); 5854642e01fSmrg } 5864642e01fSmrg 5874642e01fSmrg ret = DBUS_HANDLER_RESULT_HANDLED; 5884642e01fSmrg } 5894642e01fSmrg dbus_error_free(&error); 5904642e01fSmrg } 5914642e01fSmrg 5924642e01fSmrg return ret; 5934642e01fSmrg} 5944642e01fSmrg 5954642e01fSmrg/** 5964642e01fSmrg * Register a handler for the NameOwnerChanged signal. 5974642e01fSmrg */ 5984642e01fSmrgstatic BOOL 59935c4bbdfSmrglisten_for_startup(DBusConnection * connection, void *data) 6004642e01fSmrg{ 60135c4bbdfSmrg DBusObjectPathVTable vtable = {.message_function = ownerchanged_handler, }; 6024642e01fSmrg DBusError error; 6034642e01fSmrg const char MATCH_RULE[] = "sender='org.freedesktop.DBus'," 60435c4bbdfSmrg "interface='org.freedesktop.DBus'," 60535c4bbdfSmrg "type='signal'," 60635c4bbdfSmrg "path='/org/freedesktop/DBus'," "member='NameOwnerChanged'"; 6074642e01fSmrg int rc = FALSE; 6084642e01fSmrg 6094642e01fSmrg dbus_error_init(&error); 6104642e01fSmrg dbus_bus_add_match(connection, MATCH_RULE, &error); 6114642e01fSmrg if (!dbus_error_is_set(&error)) { 6124642e01fSmrg if (dbus_connection_register_object_path(connection, 61335c4bbdfSmrg "/org/freedesktop/DBus", 61435c4bbdfSmrg &vtable, data)) 6154642e01fSmrg rc = TRUE; 6164642e01fSmrg else 6174642e01fSmrg ErrorF("[config/hal] cannot register object path.\n"); 61835c4bbdfSmrg } 61935c4bbdfSmrg else { 6204642e01fSmrg ErrorF("[config/hal] couldn't add match rule: %s (%s)\n", error.name, 62135c4bbdfSmrg error.message); 6224642e01fSmrg ErrorF("[config/hal] cannot detect a HAL startup.\n"); 6234642e01fSmrg } 6244642e01fSmrg 6254642e01fSmrg dbus_error_free(&error); 6264642e01fSmrg 6274642e01fSmrg return rc; 6284642e01fSmrg} 6294642e01fSmrg 6304642e01fSmrgstatic void 63135c4bbdfSmrgconnect_hook(DBusConnection * connection, void *data) 6324642e01fSmrg{ 6334642e01fSmrg struct config_hal_info *info = data; 6344642e01fSmrg 6354642e01fSmrg if (listen_for_startup(connection, data) && 6364642e01fSmrg connect_and_register(connection, info)) 6374642e01fSmrg dbus_connection_unregister_object_path(connection, 6384642e01fSmrg "/org/freedesktop/DBus"); 6394642e01fSmrg 64005b261ecSmrg return; 64105b261ecSmrg} 64205b261ecSmrg 64305b261ecSmrgstatic struct config_hal_info hal_info; 64435c4bbdfSmrg 64535c4bbdfSmrgstatic struct dbus_core_hook hook = { 64605b261ecSmrg .connect = connect_hook, 64705b261ecSmrg .disconnect = disconnect_hook, 64805b261ecSmrg .data = &hal_info, 64905b261ecSmrg}; 65005b261ecSmrg 65105b261ecSmrgint 65205b261ecSmrgconfig_hal_init(void) 65305b261ecSmrg{ 65405b261ecSmrg memset(&hal_info, 0, sizeof(hal_info)); 65505b261ecSmrg hal_info.system_bus = NULL; 65605b261ecSmrg hal_info.hal_ctx = NULL; 65705b261ecSmrg 65835c4bbdfSmrg if (!dbus_core_add_hook(&hook)) { 6594642e01fSmrg LogMessage(X_ERROR, "config/hal: failed to add D-Bus hook\n"); 66005b261ecSmrg return 0; 66105b261ecSmrg } 66205b261ecSmrg 6634642e01fSmrg /* verbose message */ 66435c4bbdfSmrg LogMessageVerb(X_INFO, 7, "config/hal: initialized\n"); 6654642e01fSmrg 66605b261ecSmrg return 1; 66705b261ecSmrg} 66805b261ecSmrg 66905b261ecSmrgvoid 67005b261ecSmrgconfig_hal_fini(void) 67105b261ecSmrg{ 67235c4bbdfSmrg dbus_core_remove_hook(&hook); 67305b261ecSmrg} 674