hal.c revision b86d567b
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 3605b261ecSmrg#include "input.h" 3705b261ecSmrg#include "inputstr.h" 3805b261ecSmrg#include "hotplug.h" 3905b261ecSmrg#include "config-backends.h" 4005b261ecSmrg#include "os.h" 4105b261ecSmrg 424642e01fSmrg 434642e01fSmrg#define LIBHAL_PROP_KEY "input.x11_options." 444642e01fSmrg#define LIBHAL_XKB_PROP_KEY "input.xkb." 454642e01fSmrg 4605b261ecSmrg 4705b261ecSmrgstruct config_hal_info { 4805b261ecSmrg DBusConnection *system_bus; 4905b261ecSmrg LibHalContext *hal_ctx; 5005b261ecSmrg}; 5105b261ecSmrg 524642e01fSmrg/* Used for special handling of xkb options. */ 534642e01fSmrgstruct xkb_options { 544642e01fSmrg char* layout; 554642e01fSmrg char* model; 564642e01fSmrg char* rules; 574642e01fSmrg char* variant; 584642e01fSmrg char* options; 594642e01fSmrg}; 604642e01fSmrg 614642e01fSmrg 6205b261ecSmrgstatic void 6305b261ecSmrgremove_device(DeviceIntPtr dev) 6405b261ecSmrg{ 654642e01fSmrg /* this only gets called for devices that have already been added */ 664642e01fSmrg LogMessage(X_INFO, "config/hal: removing device %s\n", dev->name); 6705b261ecSmrg 6805b261ecSmrg /* Call PIE here so we don't try to dereference a device that's 6905b261ecSmrg * already been removed. */ 7005b261ecSmrg OsBlockSignals(); 7105b261ecSmrg ProcessInputEvents(); 7205b261ecSmrg DeleteInputDeviceRequest(dev); 7305b261ecSmrg OsReleaseSignals(); 7405b261ecSmrg} 7505b261ecSmrg 7605b261ecSmrgstatic void 7705b261ecSmrgdevice_removed(LibHalContext *ctx, const char *udi) 7805b261ecSmrg{ 7905b261ecSmrg DeviceIntPtr dev, next; 8005b261ecSmrg char *value; 8105b261ecSmrg 8205b261ecSmrg value = xalloc(strlen(udi) + 5); /* "hal:" + NULL */ 8305b261ecSmrg if (!value) 8405b261ecSmrg return; 8505b261ecSmrg sprintf(value, "hal:%s", udi); 8605b261ecSmrg 8705b261ecSmrg for (dev = inputInfo.devices; dev; dev = next) { 8805b261ecSmrg next = dev->next; 8905b261ecSmrg if (dev->config_info && strcmp(dev->config_info, value) == 0) 9005b261ecSmrg remove_device(dev); 9105b261ecSmrg } 9205b261ecSmrg for (dev = inputInfo.off_devices; dev; dev = next) { 9305b261ecSmrg next = dev->next; 9405b261ecSmrg if (dev->config_info && strcmp(dev->config_info, value) == 0) 9505b261ecSmrg remove_device(dev); 9605b261ecSmrg } 9705b261ecSmrg 9805b261ecSmrg xfree(value); 9905b261ecSmrg} 10005b261ecSmrg 10105b261ecSmrgstatic void 10205b261ecSmrgadd_option(InputOption **options, const char *key, const char *value) 10305b261ecSmrg{ 10405b261ecSmrg if (!value || *value == '\0') 10505b261ecSmrg return; 10605b261ecSmrg 10705b261ecSmrg for (; *options; options = &(*options)->next) 10805b261ecSmrg ; 10905b261ecSmrg *options = xcalloc(sizeof(**options), 1); 11005b261ecSmrg if (!*options) /* Yeesh. */ 11105b261ecSmrg return; 11205b261ecSmrg (*options)->key = xstrdup(key); 11305b261ecSmrg (*options)->value = xstrdup(value); 11405b261ecSmrg (*options)->next = NULL; 11505b261ecSmrg} 11605b261ecSmrg 11705b261ecSmrgstatic char * 11805b261ecSmrgget_prop_string(LibHalContext *hal_ctx, const char *udi, const char *name) 11905b261ecSmrg{ 12005b261ecSmrg char *prop, *ret; 12105b261ecSmrg 12205b261ecSmrg prop = libhal_device_get_property_string(hal_ctx, udi, name, NULL); 1234642e01fSmrg LogMessageVerb(X_INFO, 10, "config/hal: getting %s on %s returned %s\n", name, udi, prop ? prop : "(null)"); 12405b261ecSmrg if (prop) { 12505b261ecSmrg ret = xstrdup(prop); 12605b261ecSmrg libhal_free_string(prop); 12705b261ecSmrg } 12805b261ecSmrg else { 12905b261ecSmrg return NULL; 13005b261ecSmrg } 13105b261ecSmrg 13205b261ecSmrg return ret; 13305b261ecSmrg} 13405b261ecSmrg 13505b261ecSmrgstatic char * 13605b261ecSmrgget_prop_string_array(LibHalContext *hal_ctx, const char *udi, const char *prop) 13705b261ecSmrg{ 13805b261ecSmrg char **props, *ret, *str; 13905b261ecSmrg int i, len = 0; 14005b261ecSmrg 14105b261ecSmrg props = libhal_device_get_property_strlist(hal_ctx, udi, prop, NULL); 14205b261ecSmrg if (props) { 14305b261ecSmrg for (i = 0; props[i]; i++) 14405b261ecSmrg len += strlen(props[i]); 14505b261ecSmrg 14605b261ecSmrg ret = xcalloc(sizeof(char), len + i); /* i - 1 commas, 1 NULL */ 14705b261ecSmrg if (!ret) { 14805b261ecSmrg libhal_free_string_array(props); 14905b261ecSmrg return NULL; 15005b261ecSmrg } 15105b261ecSmrg 15205b261ecSmrg str = ret; 15305b261ecSmrg for (i = 0; props[i]; i++) { 15405b261ecSmrg strcpy(str, props[i]); 15505b261ecSmrg str += strlen(props[i]); 15605b261ecSmrg *str++ = ','; 15705b261ecSmrg } 15805b261ecSmrg *(str-1) = '\0'; 15905b261ecSmrg 16005b261ecSmrg libhal_free_string_array(props); 16105b261ecSmrg } 16205b261ecSmrg else { 16305b261ecSmrg return NULL; 16405b261ecSmrg } 16505b261ecSmrg 16605b261ecSmrg return ret; 16705b261ecSmrg} 16805b261ecSmrg 1694642e01fSmrgstatic BOOL 1704642e01fSmrgdevice_is_duplicate(char *config_info) 1714642e01fSmrg{ 1724642e01fSmrg DeviceIntPtr dev; 1734642e01fSmrg 1744642e01fSmrg for (dev = inputInfo.devices; dev; dev = dev->next) 1754642e01fSmrg { 1764642e01fSmrg if (dev->config_info && (strcmp(dev->config_info, config_info) == 0)) 1774642e01fSmrg return TRUE; 1784642e01fSmrg } 1794642e01fSmrg 1804642e01fSmrg for (dev = inputInfo.off_devices; dev; dev = dev->next) 1814642e01fSmrg { 1824642e01fSmrg if (dev->config_info && (strcmp(dev->config_info, config_info) == 0)) 1834642e01fSmrg return TRUE; 1844642e01fSmrg } 1854642e01fSmrg 1864642e01fSmrg return FALSE; 1874642e01fSmrg} 1884642e01fSmrg 18905b261ecSmrgstatic void 19005b261ecSmrgdevice_added(LibHalContext *hal_ctx, const char *udi) 19105b261ecSmrg{ 1924642e01fSmrg char *path = NULL, *driver = NULL, *name = NULL, *config_info = NULL; 19305b261ecSmrg InputOption *options = NULL, *tmpo = NULL; 1944642e01fSmrg DeviceIntPtr dev = NULL; 19505b261ecSmrg DBusError error; 1964642e01fSmrg struct xkb_options xkb_opts = {0}; 1974642e01fSmrg int rc; 19805b261ecSmrg 1994642e01fSmrg LibHalPropertySet *set = NULL; 2004642e01fSmrg LibHalPropertySetIterator set_iter; 2014642e01fSmrg char *psi_key = NULL, *tmp_val; 20205b261ecSmrg 20305b261ecSmrg 2044642e01fSmrg dbus_error_init(&error); 20505b261ecSmrg 20605b261ecSmrg driver = get_prop_string(hal_ctx, udi, "input.x11_driver"); 2074642e01fSmrg if (!driver){ 2084642e01fSmrg /* verbose, don't tell the user unless they _want_ to see it */ 2094642e01fSmrg LogMessageVerb(X_INFO,7,"config/hal: no driver specified for device %s\n", udi); 2104642e01fSmrg goto unwind; 2114642e01fSmrg } 2124642e01fSmrg 21305b261ecSmrg path = get_prop_string(hal_ctx, udi, "input.device"); 2144642e01fSmrg if (!path) { 2154642e01fSmrg LogMessage(X_WARNING,"config/hal: no driver or path specified for %s\n", udi); 21605b261ecSmrg goto unwind; 21705b261ecSmrg } 2184642e01fSmrg 21905b261ecSmrg name = get_prop_string(hal_ctx, udi, "info.product"); 22005b261ecSmrg if (!name) 22105b261ecSmrg name = xstrdup("(unnamed)"); 22205b261ecSmrg 2234642e01fSmrg options = xcalloc(sizeof(*options), 1); 2244642e01fSmrg if (!options){ 2254642e01fSmrg LogMessage(X_ERROR, "config/hal: couldn't allocate space for input options!\n"); 2264642e01fSmrg goto unwind; 22705b261ecSmrg } 22805b261ecSmrg 22905b261ecSmrg options->key = xstrdup("_source"); 23005b261ecSmrg options->value = xstrdup("server/hal"); 23105b261ecSmrg if (!options->key || !options->value) { 2324642e01fSmrg LogMessage(X_ERROR, "config/hal: couldn't allocate first key/value pair\n"); 23305b261ecSmrg goto unwind; 23405b261ecSmrg } 23505b261ecSmrg 2364642e01fSmrg /* most drivers use device.. not path. evdev uses both however, but the 2374642e01fSmrg * path version isn't documented apparently. support both for now. */ 23805b261ecSmrg add_option(&options, "path", path); 2394642e01fSmrg add_option(&options, "device", path); 2404642e01fSmrg 24105b261ecSmrg add_option(&options, "driver", driver); 24205b261ecSmrg add_option(&options, "name", name); 2434642e01fSmrg 24405b261ecSmrg config_info = xalloc(strlen(udi) + 5); /* "hal:" and NULL */ 2454642e01fSmrg if (!config_info) { 2464642e01fSmrg LogMessage(X_ERROR, "config/hal: couldn't allocate name\n"); 24705b261ecSmrg goto unwind; 2484642e01fSmrg } 24905b261ecSmrg sprintf(config_info, "hal:%s", udi); 25005b261ecSmrg 2514642e01fSmrg /* Check for duplicate devices */ 2524642e01fSmrg if (device_is_duplicate(config_info)) 2534642e01fSmrg { 2544642e01fSmrg LogMessage(X_WARNING, "config/hal: device %s already added. Ignoring.\n", name); 2554642e01fSmrg goto unwind; 2564642e01fSmrg } 2574642e01fSmrg 2584642e01fSmrg /* ok, grab options from hal.. iterate through all properties 2594642e01fSmrg * and lets see if any of them are options that we can add */ 2604642e01fSmrg set = libhal_device_get_all_properties(hal_ctx, udi, &error); 2614642e01fSmrg 2624642e01fSmrg if (!set) { 2634642e01fSmrg LogMessage(X_ERROR, "config/hal: couldn't get property list for %s: %s (%s)\n", 2644642e01fSmrg udi, error.name, error.message); 2654642e01fSmrg goto unwind; 2664642e01fSmrg } 2674642e01fSmrg 2684642e01fSmrg libhal_psi_init(&set_iter,set); 2694642e01fSmrg while (libhal_psi_has_more(&set_iter)) { 2704642e01fSmrg /* we are looking for supported keys.. extract and add to options */ 2714642e01fSmrg psi_key = libhal_psi_get_key(&set_iter); 2724642e01fSmrg 2734642e01fSmrg if (psi_key){ 2744642e01fSmrg 2754642e01fSmrg /* normal options first (input.x11_options.<propname>) */ 2764642e01fSmrg if (!strncasecmp(psi_key, LIBHAL_PROP_KEY, sizeof(LIBHAL_PROP_KEY)-1)){ 2774642e01fSmrg char* tmp; 2784642e01fSmrg 2794642e01fSmrg /* only support strings for all values */ 2804642e01fSmrg tmp_val = get_prop_string(hal_ctx, udi, psi_key); 2814642e01fSmrg 2824642e01fSmrg if (tmp_val){ 2834642e01fSmrg 2844642e01fSmrg /* xkb needs special handling. HAL specs include 2854642e01fSmrg * input.xkb.xyz options, but the x11-input.fdi specifies 2864642e01fSmrg * input.x11_options.Xkbxyz options. By default, we use 2874642e01fSmrg * the former, unless the specific X11 ones are specified. 2884642e01fSmrg * Since we can't predict the order in which the keys 2894642e01fSmrg * arrive, we need to store them. 2904642e01fSmrg */ 2914642e01fSmrg if ((tmp = strcasestr(psi_key, "xkb")) && strlen(tmp) >= 4) 2924642e01fSmrg { 2934642e01fSmrg if (!strcasecmp(&tmp[3], "layout")) 2944642e01fSmrg { 2954642e01fSmrg if (xkb_opts.layout) 2964642e01fSmrg xfree(xkb_opts.layout); 2974642e01fSmrg xkb_opts.layout = strdup(tmp_val); 2984642e01fSmrg } else if (!strcasecmp(&tmp[3], "model")) 2994642e01fSmrg { 3004642e01fSmrg if (xkb_opts.model) 3014642e01fSmrg xfree(xkb_opts.model); 3024642e01fSmrg xkb_opts.model = strdup(tmp_val); 3034642e01fSmrg } else if (!strcasecmp(&tmp[3], "rules")) 3044642e01fSmrg { 3054642e01fSmrg if (xkb_opts.rules) 3064642e01fSmrg xfree(xkb_opts.rules); 3074642e01fSmrg xkb_opts.rules = strdup(tmp_val); 3084642e01fSmrg } else if (!strcasecmp(&tmp[3], "variant")) 3094642e01fSmrg { 3104642e01fSmrg if (xkb_opts.variant) 3114642e01fSmrg xfree(xkb_opts.variant); 3124642e01fSmrg xkb_opts.variant = strdup(tmp_val); 3134642e01fSmrg } else if (!strcasecmp(&tmp[3], "options")) 3144642e01fSmrg { 3154642e01fSmrg if (xkb_opts.options) 3164642e01fSmrg xfree(xkb_opts.options); 3174642e01fSmrg xkb_opts.options = strdup(tmp_val); 3184642e01fSmrg } 3194642e01fSmrg } else 3204642e01fSmrg { 3214642e01fSmrg /* all others */ 3224642e01fSmrg add_option(&options, psi_key + sizeof(LIBHAL_PROP_KEY)-1, tmp_val); 3234642e01fSmrg xfree(tmp_val); 3244642e01fSmrg } 3254642e01fSmrg } else 3264642e01fSmrg { 3274642e01fSmrg /* server 1.4 had xkb_options as strlist. */ 3284642e01fSmrg if ((tmp = strcasestr(psi_key, "xkb")) && 3294642e01fSmrg (strlen(tmp) >= 4) && 3304642e01fSmrg (!strcasecmp(&tmp[3], "options")) && 3314642e01fSmrg (tmp_val = get_prop_string_array(hal_ctx, udi, psi_key))) 3324642e01fSmrg { 3334642e01fSmrg if (xkb_opts.options) 3344642e01fSmrg xfree(xkb_opts.options); 3354642e01fSmrg xkb_opts.options = strdup(tmp_val); 3364642e01fSmrg } 3374642e01fSmrg } 3384642e01fSmrg } else if (!strncasecmp(psi_key, LIBHAL_XKB_PROP_KEY, sizeof(LIBHAL_XKB_PROP_KEY)-1)){ 3394642e01fSmrg char* tmp; 3404642e01fSmrg 3414642e01fSmrg /* only support strings for all values */ 3424642e01fSmrg tmp_val = get_prop_string(hal_ctx, udi, psi_key); 3434642e01fSmrg 3444642e01fSmrg if (tmp_val && strlen(psi_key) >= sizeof(LIBHAL_XKB_PROP_KEY)) { 3454642e01fSmrg 3464642e01fSmrg tmp = &psi_key[sizeof(LIBHAL_XKB_PROP_KEY) - 1]; 3474642e01fSmrg 3484642e01fSmrg if (!strcasecmp(tmp, "layout")) 3494642e01fSmrg { 3504642e01fSmrg if (!xkb_opts.layout) 3514642e01fSmrg xkb_opts.layout = strdup(tmp_val); 3524642e01fSmrg } else if (!strcasecmp(tmp, "rules")) 3534642e01fSmrg { 3544642e01fSmrg if (!xkb_opts.rules) 3554642e01fSmrg xkb_opts.rules = strdup(tmp_val); 3564642e01fSmrg } else if (!strcasecmp(tmp, "variant")) 3574642e01fSmrg { 3584642e01fSmrg if (!xkb_opts.variant) 3594642e01fSmrg xkb_opts.variant = strdup(tmp_val); 3604642e01fSmrg } else if (!strcasecmp(tmp, "model")) 3614642e01fSmrg { 3624642e01fSmrg if (!xkb_opts.model) 3634642e01fSmrg xkb_opts.model = strdup(tmp_val); 3644642e01fSmrg } else if (!strcasecmp(tmp, "options")) 3654642e01fSmrg { 3664642e01fSmrg if (!xkb_opts.options) 3674642e01fSmrg xkb_opts.options = strdup(tmp_val); 3684642e01fSmrg } 3694642e01fSmrg xfree(tmp_val); 3704642e01fSmrg } else 3714642e01fSmrg { 3724642e01fSmrg /* server 1.4 had xkb options as strlist */ 3734642e01fSmrg tmp_val = get_prop_string_array(hal_ctx, udi, psi_key); 3744642e01fSmrg if (tmp_val && strlen(psi_key) >= sizeof(LIBHAL_XKB_PROP_KEY)) 3754642e01fSmrg { 3764642e01fSmrg tmp = &psi_key[sizeof(LIBHAL_XKB_PROP_KEY) - 1]; 3774642e01fSmrg if (!strcasecmp(tmp, ".options") && (!xkb_opts.options)) 3784642e01fSmrg xkb_opts.options = strdup(tmp_val); 3794642e01fSmrg } 3804642e01fSmrg } 3814642e01fSmrg } 3824642e01fSmrg } 3834642e01fSmrg 3844642e01fSmrg /* psi_key doesn't need to be freed */ 3854642e01fSmrg libhal_psi_next(&set_iter); 3864642e01fSmrg } 3874642e01fSmrg 3884642e01fSmrg 3894642e01fSmrg /* Now add xkb options */ 3904642e01fSmrg if (xkb_opts.layout) 3914642e01fSmrg add_option(&options, "xkb_layout", xkb_opts.layout); 3924642e01fSmrg if (xkb_opts.rules) 3934642e01fSmrg add_option(&options, "xkb_rules", xkb_opts.rules); 3944642e01fSmrg if (xkb_opts.variant) 3954642e01fSmrg add_option(&options, "xkb_variant", xkb_opts.variant); 3964642e01fSmrg if (xkb_opts.model) 3974642e01fSmrg add_option(&options, "xkb_model", xkb_opts.model); 3984642e01fSmrg if (xkb_opts.options) 3994642e01fSmrg add_option(&options, "xkb_options", xkb_opts.options); 4004642e01fSmrg 4014642e01fSmrg /* this isn't an error, but how else do you output something that the user can see? */ 4024642e01fSmrg LogMessage(X_INFO, "config/hal: Adding input device %s\n", name); 4034642e01fSmrg if ((rc = NewInputDeviceRequest(options, &dev)) != Success) { 4044642e01fSmrg LogMessage(X_ERROR, "config/hal: NewInputDeviceRequest failed (%d)\n", rc); 40505b261ecSmrg dev = NULL; 40605b261ecSmrg goto unwind; 40705b261ecSmrg } 40805b261ecSmrg 4094642e01fSmrg for (; dev; dev = dev->next){ 4104642e01fSmrg if (dev->config_info) 4114642e01fSmrg xfree(dev->config_info); 41205b261ecSmrg dev->config_info = xstrdup(config_info); 4134642e01fSmrg } 41405b261ecSmrg 41505b261ecSmrgunwind: 4164642e01fSmrg if (set) 4174642e01fSmrg libhal_free_property_set(set); 41805b261ecSmrg if (path) 41905b261ecSmrg xfree(path); 42005b261ecSmrg if (driver) 42105b261ecSmrg xfree(driver); 42205b261ecSmrg if (name) 42305b261ecSmrg xfree(name); 42405b261ecSmrg if (config_info) 42505b261ecSmrg xfree(config_info); 42605b261ecSmrg while (!dev && (tmpo = options)) { 42705b261ecSmrg options = tmpo->next; 42805b261ecSmrg xfree(tmpo->key); 42905b261ecSmrg xfree(tmpo->value); 43005b261ecSmrg xfree(tmpo); 43105b261ecSmrg } 43205b261ecSmrg 4334642e01fSmrg if (xkb_opts.layout) 4344642e01fSmrg xfree(xkb_opts.layout); 4354642e01fSmrg if (xkb_opts.rules) 4364642e01fSmrg xfree(xkb_opts.rules); 4374642e01fSmrg if (xkb_opts.model) 4384642e01fSmrg xfree(xkb_opts.model); 4394642e01fSmrg if (xkb_opts.variant) 4404642e01fSmrg xfree(xkb_opts.variant); 4414642e01fSmrg if (xkb_opts.options) 4424642e01fSmrg xfree(xkb_opts.options); 4434642e01fSmrg 44405b261ecSmrg dbus_error_free(&error); 44505b261ecSmrg 44605b261ecSmrg return; 44705b261ecSmrg} 44805b261ecSmrg 44905b261ecSmrgstatic void 45005b261ecSmrgdisconnect_hook(void *data) 45105b261ecSmrg{ 45205b261ecSmrg DBusError error; 45305b261ecSmrg struct config_hal_info *info = data; 45405b261ecSmrg 45505b261ecSmrg if (info->hal_ctx) { 4564642e01fSmrg if (dbus_connection_get_is_connected(info->system_bus)) { 4574642e01fSmrg dbus_error_init(&error); 4584642e01fSmrg if (!libhal_ctx_shutdown(info->hal_ctx, &error)) 4594642e01fSmrg LogMessage(X_WARNING, "config/hal: disconnect_hook couldn't shut down context: %s (%s)\n", 4604642e01fSmrg error.name, error.message); 4614642e01fSmrg dbus_error_free(&error); 4624642e01fSmrg } 46305b261ecSmrg libhal_ctx_free(info->hal_ctx); 46405b261ecSmrg } 46505b261ecSmrg 46605b261ecSmrg info->hal_ctx = NULL; 46705b261ecSmrg info->system_bus = NULL; 46805b261ecSmrg} 46905b261ecSmrg 4704642e01fSmrgstatic BOOL 4714642e01fSmrgconnect_and_register(DBusConnection *connection, struct config_hal_info *info) 47205b261ecSmrg{ 47305b261ecSmrg DBusError error; 47405b261ecSmrg char **devices; 47505b261ecSmrg int num_devices, i; 47605b261ecSmrg 477b86d567bSmrg if (info->hal_ctx) 478b86d567bSmrg return TRUE; /* already registered, pretend we did something */ 479b86d567bSmrg 48005b261ecSmrg info->system_bus = connection; 48105b261ecSmrg 48205b261ecSmrg dbus_error_init(&error); 48305b261ecSmrg 4844642e01fSmrg info->hal_ctx = libhal_ctx_new(); 48505b261ecSmrg if (!info->hal_ctx) { 4864642e01fSmrg LogMessage(X_ERROR, "config/hal: couldn't create HAL context\n"); 48705b261ecSmrg goto out_err; 48805b261ecSmrg } 48905b261ecSmrg 49005b261ecSmrg if (!libhal_ctx_set_dbus_connection(info->hal_ctx, info->system_bus)) { 4914642e01fSmrg LogMessage(X_ERROR, "config/hal: couldn't associate HAL context with bus\n"); 49205b261ecSmrg goto out_ctx; 49305b261ecSmrg } 49405b261ecSmrg if (!libhal_ctx_init(info->hal_ctx, &error)) { 4954642e01fSmrg LogMessage(X_ERROR, "config/hal: couldn't initialise context: %s (%s)\n", 496b86d567bSmrg error.name ? error.name : "unknown error", 497b86d567bSmrg error.message ? error.message : "null"); 49805b261ecSmrg goto out_ctx; 49905b261ecSmrg } 50005b261ecSmrg if (!libhal_device_property_watch_all(info->hal_ctx, &error)) { 5014642e01fSmrg LogMessage(X_ERROR, "config/hal: couldn't watch all properties: %s (%s)\n", 502b86d567bSmrg error.name ? error.name : "unknown error", 503b86d567bSmrg error.message ? error.message : "null"); 504b86d567bSmrg goto out_ctx; 50505b261ecSmrg } 50605b261ecSmrg libhal_ctx_set_device_added(info->hal_ctx, device_added); 50705b261ecSmrg libhal_ctx_set_device_removed(info->hal_ctx, device_removed); 50805b261ecSmrg 50905b261ecSmrg devices = libhal_find_device_by_capability(info->hal_ctx, "input", 51005b261ecSmrg &num_devices, &error); 51105b261ecSmrg /* FIXME: Get default devices if error is set. */ 512b86d567bSmrg if (dbus_error_is_set(&error)) { 513b86d567bSmrg LogMessage(X_ERROR, "config/hal: couldn't find input device: %s (%s)\n", 514b86d567bSmrg error.name ? error.name : "unknown error", 515b86d567bSmrg error.message ? error.message : "null"); 516b86d567bSmrg goto out_ctx; 517b86d567bSmrg } 51805b261ecSmrg for (i = 0; i < num_devices; i++) 51905b261ecSmrg device_added(info->hal_ctx, devices[i]); 52005b261ecSmrg libhal_free_string_array(devices); 52105b261ecSmrg 52205b261ecSmrg dbus_error_free(&error); 52305b261ecSmrg 5244642e01fSmrg return TRUE; 52505b261ecSmrg 52605b261ecSmrgout_ctx: 527b86d567bSmrg dbus_error_free(&error); 528b86d567bSmrg 529b86d567bSmrg if (info->hal_ctx) { 530b86d567bSmrg if (!libhal_ctx_shutdown(info->hal_ctx, &error)) { 531b86d567bSmrg LogMessage(X_WARNING, "config/hal: couldn't shut down context: %s (%s)\n", 532b86d567bSmrg error.name ? error.name : "unknown error", 533b86d567bSmrg error.message ? error.message : "null"); 534b86d567bSmrg dbus_error_free(&error); 535b86d567bSmrg } 536b86d567bSmrg libhal_ctx_free(info->hal_ctx); 537b86d567bSmrg } 538b86d567bSmrg 53905b261ecSmrgout_err: 54005b261ecSmrg dbus_error_free(&error); 54105b261ecSmrg 54205b261ecSmrg info->hal_ctx = NULL; 54305b261ecSmrg info->system_bus = NULL; 54405b261ecSmrg 5454642e01fSmrg return FALSE; 5464642e01fSmrg} 5474642e01fSmrg 5484642e01fSmrg 5494642e01fSmrg/** 5504642e01fSmrg * Handle NewOwnerChanged signals to deal with HAL startup at X server runtime. 5514642e01fSmrg * 5524642e01fSmrg * NewOwnerChanged is send once when HAL shuts down, and once again when it 5534642e01fSmrg * comes back up. Message has three arguments, first is the name 5544642e01fSmrg * (org.freedesktop.Hal), the second one is the old owner, third one is new 5554642e01fSmrg * owner. 5564642e01fSmrg */ 5574642e01fSmrgstatic DBusHandlerResult 5584642e01fSmrgownerchanged_handler(DBusConnection *connection, DBusMessage *message, void *data) 5594642e01fSmrg{ 5604642e01fSmrg int ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 5614642e01fSmrg 5624642e01fSmrg if (dbus_message_is_signal(message, 5634642e01fSmrg "org.freedesktop.DBus", 5644642e01fSmrg "NameOwnerChanged")) { 5654642e01fSmrg DBusError error; 5664642e01fSmrg char *name, *old_owner, *new_owner; 5674642e01fSmrg 5684642e01fSmrg dbus_error_init(&error); 5694642e01fSmrg dbus_message_get_args(message, &error, 5704642e01fSmrg DBUS_TYPE_STRING, &name, 5714642e01fSmrg DBUS_TYPE_STRING, &old_owner, 5724642e01fSmrg DBUS_TYPE_STRING, &new_owner, 5734642e01fSmrg DBUS_TYPE_INVALID); 5744642e01fSmrg 5754642e01fSmrg if (dbus_error_is_set(&error)) { 5764642e01fSmrg ErrorF("[config/hal] failed to get NameOwnerChanged args: %s (%s)\n", 5774642e01fSmrg error.name, error.message); 5784642e01fSmrg } else if (name && strcmp(name, "org.freedesktop.Hal") == 0) { 5794642e01fSmrg 5804642e01fSmrg if (!old_owner || !strlen(old_owner)) { 5814642e01fSmrg DebugF("[config/hal] HAL startup detected.\n"); 5824642e01fSmrg if (connect_and_register(connection, (struct config_hal_info*)data)) 5834642e01fSmrg dbus_connection_unregister_object_path(connection, 5844642e01fSmrg "/org/freedesktop/DBus"); 5854642e01fSmrg else 5864642e01fSmrg ErrorF("[config/hal] Failed to connect to HAL bus.\n"); 5874642e01fSmrg } 5884642e01fSmrg 5894642e01fSmrg ret = DBUS_HANDLER_RESULT_HANDLED; 5904642e01fSmrg } 5914642e01fSmrg dbus_error_free(&error); 5924642e01fSmrg } 5934642e01fSmrg 5944642e01fSmrg return ret; 5954642e01fSmrg} 5964642e01fSmrg 5974642e01fSmrg/** 5984642e01fSmrg * Register a handler for the NameOwnerChanged signal. 5994642e01fSmrg */ 6004642e01fSmrgstatic BOOL 6014642e01fSmrglisten_for_startup(DBusConnection *connection, void *data) 6024642e01fSmrg{ 6034642e01fSmrg DBusObjectPathVTable vtable = { .message_function = ownerchanged_handler, }; 6044642e01fSmrg DBusError error; 6054642e01fSmrg const char MATCH_RULE[] = "sender='org.freedesktop.DBus'," 6064642e01fSmrg "interface='org.freedesktop.DBus'," 6074642e01fSmrg "type='signal'," 6084642e01fSmrg "path='/org/freedesktop/DBus'," 6094642e01fSmrg "member='NameOwnerChanged'"; 6104642e01fSmrg int rc = FALSE; 6114642e01fSmrg 6124642e01fSmrg dbus_error_init(&error); 6134642e01fSmrg dbus_bus_add_match(connection, MATCH_RULE, &error); 6144642e01fSmrg if (!dbus_error_is_set(&error)) { 6154642e01fSmrg if (dbus_connection_register_object_path(connection, 6164642e01fSmrg "/org/freedesktop/DBus", 6174642e01fSmrg &vtable, 6184642e01fSmrg data)) 6194642e01fSmrg rc = TRUE; 6204642e01fSmrg else 6214642e01fSmrg ErrorF("[config/hal] cannot register object path.\n"); 6224642e01fSmrg } else { 6234642e01fSmrg ErrorF("[config/hal] couldn't add match rule: %s (%s)\n", error.name, 6244642e01fSmrg error.message); 6254642e01fSmrg ErrorF("[config/hal] cannot detect a HAL startup.\n"); 6264642e01fSmrg } 6274642e01fSmrg 6284642e01fSmrg dbus_error_free(&error); 6294642e01fSmrg 6304642e01fSmrg return rc; 6314642e01fSmrg} 6324642e01fSmrg 6334642e01fSmrgstatic void 6344642e01fSmrgconnect_hook(DBusConnection *connection, void *data) 6354642e01fSmrg{ 6364642e01fSmrg struct config_hal_info *info = data; 6374642e01fSmrg 6384642e01fSmrg if (listen_for_startup(connection, data) && 6394642e01fSmrg connect_and_register(connection, info)) 6404642e01fSmrg dbus_connection_unregister_object_path(connection, 6414642e01fSmrg "/org/freedesktop/DBus"); 6424642e01fSmrg 64305b261ecSmrg return; 64405b261ecSmrg} 64505b261ecSmrg 64605b261ecSmrgstatic struct config_hal_info hal_info; 64705b261ecSmrgstatic struct config_dbus_core_hook hook = { 64805b261ecSmrg .connect = connect_hook, 64905b261ecSmrg .disconnect = disconnect_hook, 65005b261ecSmrg .data = &hal_info, 65105b261ecSmrg}; 65205b261ecSmrg 65305b261ecSmrgint 65405b261ecSmrgconfig_hal_init(void) 65505b261ecSmrg{ 65605b261ecSmrg memset(&hal_info, 0, sizeof(hal_info)); 65705b261ecSmrg hal_info.system_bus = NULL; 65805b261ecSmrg hal_info.hal_ctx = NULL; 65905b261ecSmrg 66005b261ecSmrg if (!config_dbus_core_add_hook(&hook)) { 6614642e01fSmrg LogMessage(X_ERROR, "config/hal: failed to add D-Bus hook\n"); 66205b261ecSmrg return 0; 66305b261ecSmrg } 66405b261ecSmrg 6654642e01fSmrg /* verbose message */ 6664642e01fSmrg LogMessageVerb(X_INFO,7,"config/hal: initialized"); 6674642e01fSmrg 66805b261ecSmrg return 1; 66905b261ecSmrg} 67005b261ecSmrg 67105b261ecSmrgvoid 67205b261ecSmrgconfig_hal_fini(void) 67305b261ecSmrg{ 67405b261ecSmrg config_dbus_core_remove_hook(&hook); 67505b261ecSmrg} 676