parent
9335ee7994
commit
23296633bb
|
@ -72,7 +72,7 @@ cache:
|
|||
- '%CYGWIN_ROOT%\home\%USERNAME%\.ccache'
|
||||
build_script:
|
||||
- SET PATH=%CYGWIN_ROOT%/bin
|
||||
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; meson setup --prefix=/usr -Dxv=false -Dxf86bigfont=true -Dxvfb=true -Dhal=false -Dudev=false build"'
|
||||
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; meson setup --prefix=/usr -Dxv=false -Dxf86bigfont=true -Dxvfb=true build"'
|
||||
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; meson configure build"'
|
||||
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; ninja -C build"'
|
||||
- '%CYGWIN_ROOT%/bin/bash -lc "cd $APPVEYOR_BUILD_FOLDER; ccache -s"'
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
# Collection of quirks and blacklist/whitelists for specific devices.
|
||||
|
||||
|
||||
# Accelerometer device, posts data through ABS_X/ABS_Y, making X unusable
|
||||
# http://bugs.freedesktop.org/show_bug.cgi?id=22442
|
||||
Section "InputClass"
|
||||
Identifier "ThinkPad HDAPS accelerometer blacklist"
|
||||
MatchProduct "ThinkPad HDAPS accelerometer data"
|
||||
Option "Ignore" "on"
|
||||
EndSection
|
||||
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=523914
|
||||
# Mouse does not move in PV Xen guest
|
||||
# Explicitly tell evdev to not ignore the absolute axes.
|
||||
Section "InputClass"
|
||||
Identifier "Xen Virtual Pointer axis blacklist"
|
||||
MatchProduct "Xen Virtual Pointer"
|
||||
Option "IgnoreAbsoluteAxes" "off"
|
||||
Option "IgnoreRelativeAxes" "off"
|
||||
EndSection
|
||||
|
||||
# https://bugs.freedesktop.org/show_bug.cgi?id=55867
|
||||
# Bug 55867 - Doesn't know how to tag XI_TRACKBALL
|
||||
Section "InputClass"
|
||||
Identifier "Tag trackballs as XI_TRACKBALL"
|
||||
MatchProduct "trackball"
|
||||
MatchDriver "evdev"
|
||||
Option "TypeName" "TRACKBALL"
|
||||
EndSection
|
||||
|
||||
# https://bugs.freedesktop.org/show_bug.cgi?id=62831
|
||||
# Bug 62831 - Mionix Naos 5000 mouse detected incorrectly
|
||||
Section "InputClass"
|
||||
Identifier "Tag Mionix Naos 5000 mouse XI_MOUSE"
|
||||
MatchProduct "La-VIEW Technology Naos 5000 Mouse"
|
||||
MatchDriver "evdev"
|
||||
Option "TypeName" "MOUSE"
|
||||
EndSection
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2006-2007 Daniel Stone
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Author: Daniel Stone <daniel@fooishbar.org>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
#include "input.h"
|
||||
#include "list.h"
|
||||
|
||||
void remove_devices(const char *backend, const char *config_info);
|
||||
BOOL device_is_duplicate(const char *config_info);
|
||||
|
||||
#ifdef CONFIG_UDEV
|
||||
int config_udev_pre_init(void);
|
||||
int config_udev_init(void);
|
||||
void config_udev_fini(void);
|
||||
void config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback);
|
||||
#elif defined(CONFIG_HAL)
|
||||
int config_hal_init(void);
|
||||
void config_hal_fini(void);
|
||||
#elif defined(CONFIG_WSCONS)
|
||||
int config_wscons_init(void);
|
||||
void config_wscons_fini(void);
|
||||
#endif
|
151
config/config.c
151
config/config.c
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2006-2007 Daniel Stone
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Author: Daniel Stone <daniel@fooishbar.org>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include "os.h"
|
||||
#include "inputstr.h"
|
||||
#include "hotplug.h"
|
||||
#include "config-backends.h"
|
||||
#include "systemd-logind.h"
|
||||
|
||||
void
|
||||
config_pre_init(void)
|
||||
{
|
||||
#ifdef CONFIG_UDEV
|
||||
if (!config_udev_pre_init())
|
||||
ErrorF("[config] failed to pre-init udev\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
config_init(void)
|
||||
{
|
||||
#ifdef CONFIG_UDEV
|
||||
if (!config_udev_init())
|
||||
ErrorF("[config] failed to initialise udev\n");
|
||||
#elif defined(CONFIG_HAL)
|
||||
if (!config_hal_init())
|
||||
ErrorF("[config] failed to initialise HAL\n");
|
||||
#elif defined(CONFIG_WSCONS)
|
||||
if (!config_wscons_init())
|
||||
ErrorF("[config] failed to initialise wscons\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
config_fini(void)
|
||||
{
|
||||
#if defined(CONFIG_UDEV)
|
||||
config_udev_fini();
|
||||
#elif defined(CONFIG_HAL)
|
||||
config_hal_fini();
|
||||
#elif defined(CONFIG_WSCONS)
|
||||
config_wscons_fini();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
config_odev_probe(config_odev_probe_proc_ptr probe_callback)
|
||||
{
|
||||
#if defined(CONFIG_UDEV_KMS)
|
||||
config_udev_odev_probe(probe_callback);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
remove_device(const char *backend, DeviceIntPtr dev)
|
||||
{
|
||||
/* this only gets called for devices that have already been added */
|
||||
LogMessage(X_INFO, "config/%s: removing device %s\n", backend, dev->name);
|
||||
|
||||
/* Call PIE here so we don't try to dereference a device that's
|
||||
* already been removed. */
|
||||
input_lock();
|
||||
ProcessInputEvents();
|
||||
DeleteInputDeviceRequest(dev);
|
||||
input_unlock();
|
||||
}
|
||||
|
||||
void
|
||||
remove_devices(const char *backend, const char *config_info)
|
||||
{
|
||||
DeviceIntPtr dev, next;
|
||||
|
||||
for (dev = inputInfo.devices; dev; dev = next) {
|
||||
next = dev->next;
|
||||
if (dev->config_info && strcmp(dev->config_info, config_info) == 0)
|
||||
remove_device(backend, dev);
|
||||
}
|
||||
for (dev = inputInfo.off_devices; dev; dev = next) {
|
||||
next = dev->next;
|
||||
if (dev->config_info && strcmp(dev->config_info, config_info) == 0)
|
||||
remove_device(backend, dev);
|
||||
}
|
||||
|
||||
RemoveInputDeviceTraces(config_info);
|
||||
}
|
||||
|
||||
BOOL
|
||||
device_is_duplicate(const char *config_info)
|
||||
{
|
||||
DeviceIntPtr dev;
|
||||
|
||||
for (dev = inputInfo.devices; dev; dev = dev->next) {
|
||||
if (dev->config_info && (strcmp(dev->config_info, config_info) == 0))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
for (dev = inputInfo.off_devices; dev; dev = dev->next) {
|
||||
if (dev->config_info && (strcmp(dev->config_info, config_info) == 0))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
struct OdevAttributes *
|
||||
config_odev_allocate_attributes(void)
|
||||
{
|
||||
struct OdevAttributes *attribs =
|
||||
xnfcalloc(1, sizeof (struct OdevAttributes));
|
||||
attribs->fd = -1;
|
||||
return attribs;
|
||||
}
|
||||
|
||||
void
|
||||
config_odev_free_attributes(struct OdevAttributes *attribs)
|
||||
{
|
||||
if (attribs->fd != -1)
|
||||
systemd_logind_release_fd(attribs->major, attribs->minor, attribs->fd);
|
||||
free(attribs->path);
|
||||
free(attribs->syspath);
|
||||
free(attribs->busid);
|
||||
free(attribs->driver);
|
||||
free(attribs);
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
D-BUS Configuration API v2
|
||||
----------------------------
|
||||
|
||||
The X server will register the bus name org.x.config.displayN, and the
|
||||
object /org/x/config/N, where N is the display number.
|
||||
|
||||
Currently only hotplugging of input devices is supported.
|
||||
|
||||
org.x.config.input:
|
||||
org.x.config.input.version:
|
||||
Returns one unsigned int32, which is the API version.
|
||||
|
||||
org.x.config.input.add:
|
||||
Takes an argument of key/value option pairs in arrays, e.g.:
|
||||
[ss][ss][ss][ss]
|
||||
is the signature for four options. These options will be passed
|
||||
to the input driver as with any others.
|
||||
Option names beginning with _ are not allowed; they are reserved
|
||||
for internal use.
|
||||
|
||||
Returns a number of signed int32s. Positive integers are the
|
||||
device IDs of new devices; negative numbers are X error codes,
|
||||
as defined in X.h. BadMatch will be returned if the options
|
||||
given do not match any device. BadValue is returned for a malformed
|
||||
message. (Example: 8 is new device ID 8; -8 is BadMatch.)
|
||||
|
||||
Notably, BadAlloc is never returned: the server internally signals
|
||||
to D-BUS that the attempt failed for lack of memory.
|
||||
|
||||
org.x.config.input.remove:
|
||||
Takes one uint32 argument, which is the device ID to remove, i.e.:
|
||||
u
|
||||
is the signature.
|
||||
|
||||
Returns one signed int32 which represents an X status as defined in
|
||||
X.h. See org.x.config.input.add. Error codes are negative numbers.
|
||||
|
||||
org.x.config.input.listDevices:
|
||||
Lists the currently active devices. No argument.
|
||||
Return value is sequence of [<id> <name>] [<id> <name>] ..., i.e. [us].
|
|
@ -1,238 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2006-2007 Daniel Stone
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Author: Daniel Stone <daniel@fooishbar.org>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include "dix.h"
|
||||
#include "os.h"
|
||||
#include "dbus-core.h"
|
||||
|
||||
/* How often to attempt reconnecting when we get booted off the bus. */
|
||||
#define RECONNECT_DELAY (10 * 1000) /* in ms */
|
||||
|
||||
struct dbus_core_info {
|
||||
int fd;
|
||||
DBusConnection *connection;
|
||||
OsTimerPtr timer;
|
||||
struct dbus_core_hook *hooks;
|
||||
};
|
||||
static struct dbus_core_info bus_info = { .fd = -1 };
|
||||
|
||||
static CARD32 reconnect_timer(OsTimerPtr timer, CARD32 time, void *arg);
|
||||
|
||||
static void
|
||||
socket_handler(int fd, int ready, void *data)
|
||||
{
|
||||
struct dbus_core_info *info = data;
|
||||
|
||||
if (info->connection) {
|
||||
do {
|
||||
dbus_connection_read_write_dispatch(info->connection, 0);
|
||||
} while (info->connection &&
|
||||
dbus_connection_get_is_connected(info->connection) &&
|
||||
dbus_connection_get_dispatch_status(info->connection) ==
|
||||
DBUS_DISPATCH_DATA_REMAINS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect (if we haven't already been forcefully disconnected), clean up
|
||||
* after ourselves, and call all registered disconnect hooks.
|
||||
*/
|
||||
static void
|
||||
teardown(void)
|
||||
{
|
||||
struct dbus_core_hook *hook;
|
||||
|
||||
if (bus_info.timer) {
|
||||
TimerFree(bus_info.timer);
|
||||
bus_info.timer = NULL;
|
||||
}
|
||||
|
||||
/* We should really have pre-disconnect hooks and run them here, for
|
||||
* completeness. But then it gets awkward, given that you can't
|
||||
* guarantee that they'll be called ... */
|
||||
if (bus_info.connection)
|
||||
dbus_connection_unref(bus_info.connection);
|
||||
|
||||
if (bus_info.fd != -1)
|
||||
RemoveNotifyFd(bus_info.fd);
|
||||
bus_info.fd = -1;
|
||||
bus_info.connection = NULL;
|
||||
|
||||
for (hook = bus_info.hooks; hook; hook = hook->next) {
|
||||
if (hook->disconnect)
|
||||
hook->disconnect(hook->data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a filter, which only handles the disconnected signal, which
|
||||
* doesn't go to the normal message handling function. This takes
|
||||
* precedence over the message handling function, so have have to be
|
||||
* careful to ignore anything we don't want to deal with here.
|
||||
*/
|
||||
static DBusHandlerResult
|
||||
message_filter(DBusConnection * connection, DBusMessage * message, void *data)
|
||||
{
|
||||
/* If we get disconnected, then take everything down, and attempt to
|
||||
* reconnect immediately (assuming it's just a restart). The
|
||||
* connection isn't valid at this point, so throw it out immediately. */
|
||||
if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
|
||||
DebugF("[dbus-core] disconnected from bus\n");
|
||||
bus_info.connection = NULL;
|
||||
teardown();
|
||||
|
||||
if (bus_info.timer)
|
||||
TimerFree(bus_info.timer);
|
||||
bus_info.timer = TimerSet(NULL, 0, 1, reconnect_timer, NULL);
|
||||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to connect to the system bus, and set a filter to deal with
|
||||
* disconnection (see message_filter above).
|
||||
*
|
||||
* @return 1 on success, 0 on failure.
|
||||
*/
|
||||
static int
|
||||
connect_to_bus(void)
|
||||
{
|
||||
DBusError error;
|
||||
struct dbus_core_hook *hook;
|
||||
|
||||
dbus_error_init(&error);
|
||||
bus_info.connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
|
||||
if (!bus_info.connection || dbus_error_is_set(&error)) {
|
||||
LogMessage(X_ERROR, "dbus-core: error connecting to system bus: %s (%s)\n",
|
||||
error.name, error.message);
|
||||
goto err_begin;
|
||||
}
|
||||
|
||||
/* Thankyou. Really, thankyou. */
|
||||
dbus_connection_set_exit_on_disconnect(bus_info.connection, FALSE);
|
||||
|
||||
if (!dbus_connection_get_unix_fd(bus_info.connection, &bus_info.fd)) {
|
||||
ErrorF("[dbus-core] couldn't get fd for system bus\n");
|
||||
goto err_unref;
|
||||
}
|
||||
|
||||
if (!dbus_connection_add_filter(bus_info.connection, message_filter,
|
||||
&bus_info, NULL)) {
|
||||
ErrorF("[dbus-core] couldn't add filter: %s (%s)\n", error.name,
|
||||
error.message);
|
||||
goto err_fd;
|
||||
}
|
||||
|
||||
dbus_error_free(&error);
|
||||
SetNotifyFd(bus_info.fd, socket_handler, X_NOTIFY_READ, &bus_info);
|
||||
|
||||
for (hook = bus_info.hooks; hook; hook = hook->next) {
|
||||
if (hook->connect)
|
||||
hook->connect(bus_info.connection, hook->data);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
err_fd:
|
||||
bus_info.fd = -1;
|
||||
err_unref:
|
||||
dbus_connection_unref(bus_info.connection);
|
||||
bus_info.connection = NULL;
|
||||
err_begin:
|
||||
dbus_error_free(&error);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static CARD32
|
||||
reconnect_timer(OsTimerPtr timer, CARD32 time, void *arg)
|
||||
{
|
||||
if (connect_to_bus()) {
|
||||
TimerFree(bus_info.timer);
|
||||
bus_info.timer = NULL;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return RECONNECT_DELAY;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
dbus_core_add_hook(struct dbus_core_hook *hook)
|
||||
{
|
||||
struct dbus_core_hook **prev;
|
||||
|
||||
for (prev = &bus_info.hooks; *prev; prev = &(*prev)->next);
|
||||
|
||||
hook->next = NULL;
|
||||
*prev = hook;
|
||||
|
||||
/* If we're already connected, call the connect hook. */
|
||||
if (bus_info.connection)
|
||||
hook->connect(bus_info.connection, hook->data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
dbus_core_remove_hook(struct dbus_core_hook *hook)
|
||||
{
|
||||
struct dbus_core_hook **prev;
|
||||
|
||||
for (prev = &bus_info.hooks; *prev; prev = &(*prev)->next) {
|
||||
if (*prev == hook) {
|
||||
*prev = hook->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
dbus_core_init(void)
|
||||
{
|
||||
memset(&bus_info, 0, sizeof(bus_info));
|
||||
bus_info.fd = -1;
|
||||
bus_info.hooks = NULL;
|
||||
if (!connect_to_bus())
|
||||
bus_info.timer = TimerSet(NULL, 0, 1, reconnect_timer, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
dbus_core_fini(void)
|
||||
{
|
||||
teardown();
|
||||
}
|
|
@ -1,202 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# Convert xorg keys from hal FDIs files to xorg.conf InputClass sections.
|
||||
# Modified from Martin Pitt's original fdi2mpi.py script:
|
||||
# http://cgit.freedesktop.org/media-player-info/tree/tools/fdi2mpi.py
|
||||
#
|
||||
# (C) 2010 Dan Nicholson
|
||||
# (C) 2009 Canonical Ltd.
|
||||
# Author: Dan Nicholson <dbn.lists@gmail.com>
|
||||
# Author: Martin Pitt <martin.pitt@ubuntu.com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# fur- nished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FIT- NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
# THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
|
||||
# NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import sys, xml.dom.minidom
|
||||
|
||||
# dict converting <match> tags to Match* entries
|
||||
match_table = {
|
||||
'info.product': 'MatchProduct',
|
||||
'input.product': 'MatchProduct',
|
||||
'info.vendor': 'MatchVendor',
|
||||
'input.vendor': 'MatchVendor',
|
||||
'info.device': 'MatchDevicePath',
|
||||
'linux.device_file': 'MatchDevicePath',
|
||||
'/org/freedesktop/Hal/devices/computer:system.kernel.name': 'MatchOS',
|
||||
'@info.parent:pnp.id': 'MatchPnPID',
|
||||
}
|
||||
|
||||
# dict converting info.capabilities list to Match* entries
|
||||
cap_match_table = {
|
||||
'input.keys': 'MatchIsKeyboard',
|
||||
'input.keyboard': 'MatchIsKeyboard',
|
||||
'input.keypad': 'MatchIsKeyboard',
|
||||
'input.mouse': 'MatchIsPointer',
|
||||
'input.joystick': 'MatchIsJoystick',
|
||||
'input.tablet': 'MatchIsTablet',
|
||||
'input.touchpad': 'MatchIsTouchpad',
|
||||
'input.touchscreen': 'MatchIsTouchscreen',
|
||||
}
|
||||
|
||||
def device_glob(path):
|
||||
'''Convert a contains device path to a glob entry'''
|
||||
if path[0] != '/':
|
||||
path = '*' + path
|
||||
return path + '*'
|
||||
|
||||
def parse_match(node):
|
||||
'''Parse a <match> tag to a tuple with InputClass values'''
|
||||
match = None
|
||||
value = None
|
||||
booltype = False
|
||||
|
||||
# see what type of key we have
|
||||
if node.attributes.has_key('key'):
|
||||
key = node.attributes['key'].nodeValue
|
||||
if key in match_table:
|
||||
match = match_table[key]
|
||||
elif key == 'info.capabilities':
|
||||
booltype = True
|
||||
|
||||
# bail out now if it's unrecognized
|
||||
if not match and not booltype:
|
||||
return (match, value)
|
||||
|
||||
if node.attributes.has_key('string'):
|
||||
value = node.attributes['string'].nodeValue
|
||||
elif node.attributes.has_key('contains'):
|
||||
value = node.attributes['contains'].nodeValue
|
||||
if match == 'MatchDevicePath':
|
||||
value = device_glob(value)
|
||||
elif booltype and value in cap_match_table:
|
||||
match = cap_match_table[value]
|
||||
value = 'yes'
|
||||
elif node.attributes.has_key('string_outof'):
|
||||
value = node.attributes['string_outof'].nodeValue.replace(';','|')
|
||||
elif node.attributes.has_key('contains_outof'):
|
||||
all_values = node.attributes['contains_outof'].nodeValue.split(';')
|
||||
for v in all_values:
|
||||
if match == 'MatchDevicePath':
|
||||
v = device_glob(v)
|
||||
elif match == 'MatchPnPID' and len(v) < 7:
|
||||
v += '*'
|
||||
if value:
|
||||
value += '|' + v
|
||||
else:
|
||||
value = v
|
||||
|
||||
return (match, value)
|
||||
|
||||
def parse_options(node):
|
||||
'''Parse the x11_* options and return InputClass entries'''
|
||||
driver = ''
|
||||
ignore = False
|
||||
options = []
|
||||
for n in node.childNodes:
|
||||
if n.nodeType != xml.dom.minidom.Node.ELEMENT_NODE:
|
||||
continue
|
||||
|
||||
tag = n.tagName
|
||||
key = n.attributes['key'].nodeValue
|
||||
value = ''
|
||||
|
||||
if n.hasChildNodes():
|
||||
content_node = n.childNodes[0]
|
||||
assert content_node.nodeType == xml.dom.Node.TEXT_NODE
|
||||
value = content_node.nodeValue
|
||||
|
||||
if tag == 'match':
|
||||
continue
|
||||
assert tag in ('addset', 'merge', 'append', 'remove')
|
||||
|
||||
if tag == 'remove' and key == 'input.x11_driver':
|
||||
ignore = True
|
||||
elif key == 'input.x11_driver':
|
||||
driver = value
|
||||
elif key.startswith('input.x11_options.'):
|
||||
option = key.split('.', 2)[2]
|
||||
options.append((option, value))
|
||||
|
||||
return (driver, ignore, options)
|
||||
|
||||
def is_match_node(node):
|
||||
'''Check if a node is a <match> element'''
|
||||
return node.nodeType == xml.dom.minidom.Node.ELEMENT_NODE and \
|
||||
node.tagName == 'match'
|
||||
|
||||
def parse_all_matches(node):
|
||||
'''Parse a x11 match tag and any parents that don't supply their
|
||||
own options'''
|
||||
matches = []
|
||||
|
||||
while True:
|
||||
(key, value) = parse_match(node)
|
||||
if key and value:
|
||||
matches.append((key, value))
|
||||
|
||||
# walk up to a parent match node
|
||||
node = node.parentNode
|
||||
if node == None or not is_match_node(node):
|
||||
break
|
||||
|
||||
# leave if there other options at this level
|
||||
children = set([n.tagName for n in node.childNodes
|
||||
if n.nodeType == xml.dom.minidom.Node.ELEMENT_NODE])
|
||||
if children & set(['addset', 'merge', 'append']):
|
||||
break
|
||||
|
||||
return matches
|
||||
|
||||
# stupid counter to give "unique" rule names
|
||||
num_sections = 1
|
||||
def print_section(matches, driver, ignore, options):
|
||||
'''Print a valid InputClass section to stdout'''
|
||||
global num_sections
|
||||
print 'Section "InputClass"'
|
||||
print '\tIdentifier "Converted Class %d"' % num_sections
|
||||
num_sections += 1
|
||||
for m, v in matches:
|
||||
print '\t%s "%s"' % (m, v)
|
||||
if driver:
|
||||
print '\tDriver "%s"' % driver
|
||||
if ignore:
|
||||
print '\tOption "Ignore" "yes"'
|
||||
for o, v in options:
|
||||
print '\tOption "%s" "%s"' % (o, v)
|
||||
print 'EndSection'
|
||||
|
||||
def parse_fdi(fdi):
|
||||
'''Parse x11 matches from fdi'''
|
||||
# find all <match> leaf nodes
|
||||
num = 0
|
||||
for match_node in fdi.getElementsByTagName('match'):
|
||||
children = set([n.tagName for n in match_node.childNodes
|
||||
if n.nodeType == xml.dom.minidom.Node.ELEMENT_NODE])
|
||||
|
||||
# see if there are any options at this level
|
||||
(driver, ignore, options) = parse_options(match_node)
|
||||
if not driver and not ignore and not options:
|
||||
continue
|
||||
|
||||
matches = parse_all_matches(match_node)
|
||||
if num > 0:
|
||||
print
|
||||
print_section(matches, driver, ignore, options)
|
||||
num += 1
|
||||
|
||||
for f in sys.argv[1:]:
|
||||
parse_fdi(xml.dom.minidom.parse(f))
|
675
config/hal.c
675
config/hal.c
|
@ -1,675 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2007 Daniel Stone
|
||||
* Copyright © 2007 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Author: Daniel Stone <daniel@fooishbar.org>
|
||||
*/
|
||||
|
||||
#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 "dbus-core.h"
|
||||
#include "input.h"
|
||||
#include "inputstr.h"
|
||||
#include "hotplug.h"
|
||||
#include "config-backends.h"
|
||||
#include "os.h"
|
||||
|
||||
#define LIBHAL_PROP_KEY "input.x11_options."
|
||||
#define LIBHAL_XKB_PROP_KEY "input.xkb."
|
||||
|
||||
struct config_hal_info {
|
||||
DBusConnection *system_bus;
|
||||
LibHalContext *hal_ctx;
|
||||
};
|
||||
|
||||
/* Used for special handling of xkb options. */
|
||||
struct xkb_options {
|
||||
char *layout;
|
||||
char *model;
|
||||
char *rules;
|
||||
char *variant;
|
||||
char *options;
|
||||
};
|
||||
|
||||
static void
|
||||
device_removed(LibHalContext * ctx, const char *udi)
|
||||
{
|
||||
char *value;
|
||||
|
||||
if (asprintf(&value, "hal:%s", udi) == -1)
|
||||
return;
|
||||
|
||||
remove_devices("hal", value);
|
||||
|
||||
free(value);
|
||||
}
|
||||
|
||||
static char *
|
||||
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);
|
||||
LogMessageVerb(X_INFO, 10, "config/hal: getting %s on %s returned %s\n",
|
||||
name, udi, prop ? prop : "(null)");
|
||||
if (prop) {
|
||||
ret = strdup(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)
|
||||
{
|
||||
char **props, *ret, *str;
|
||||
int i, len = 0;
|
||||
|
||||
props = libhal_device_get_property_strlist(hal_ctx, udi, prop, NULL);
|
||||
if (props) {
|
||||
for (i = 0; props[i]; i++)
|
||||
len += strlen(props[i]);
|
||||
|
||||
ret = calloc(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++) {
|
||||
strcpy(str, props[i]);
|
||||
str += strlen(props[i]);
|
||||
*str++ = ',';
|
||||
}
|
||||
*(str - 1) = '\0';
|
||||
|
||||
libhal_free_string_array(props);
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
device_added(LibHalContext * hal_ctx, const char *udi)
|
||||
{
|
||||
char *path = NULL, *driver = NULL, *name = NULL, *config_info = NULL;
|
||||
char *hal_tags, *parent;
|
||||
InputOption *input_options = NULL;
|
||||
InputAttributes attrs = { 0 };
|
||||
DeviceIntPtr dev = NULL;
|
||||
DBusError error;
|
||||
struct xkb_options xkb_opts = { 0 };
|
||||
int rc;
|
||||
|
||||
LibHalPropertySet *set = NULL;
|
||||
LibHalPropertySetIterator set_iter;
|
||||
char *psi_key = NULL, *tmp_val;
|
||||
|
||||
dbus_error_init(&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 (!path) {
|
||||
LogMessage(X_WARNING,
|
||||
"config/hal: no driver or path specified for %s\n", udi);
|
||||
goto unwind;
|
||||
}
|
||||
attrs.device = strdup(path);
|
||||
|
||||
name = get_prop_string(hal_ctx, udi, "info.product");
|
||||
if (!name)
|
||||
name = strdup("(unnamed)");
|
||||
else
|
||||
attrs.product = strdup(name);
|
||||
|
||||
attrs.vendor = get_prop_string(hal_ctx, udi, "info.vendor");
|
||||
hal_tags = get_prop_string(hal_ctx, udi, "input.tags");
|
||||
attrs.tags = xstrtokenize(hal_tags, ",");
|
||||
free(hal_tags);
|
||||
|
||||
if (libhal_device_query_capability(hal_ctx, udi, "input.keys", NULL))
|
||||
attrs.flags |= ATTR_KEY | ATTR_KEYBOARD;
|
||||
if (libhal_device_query_capability(hal_ctx, udi, "input.mouse", NULL))
|
||||
attrs.flags |= ATTR_POINTER;
|
||||
if (libhal_device_query_capability(hal_ctx, udi, "input.joystick", NULL))
|
||||
attrs.flags |= ATTR_JOYSTICK;
|
||||
if (libhal_device_query_capability(hal_ctx, udi, "input.tablet", NULL))
|
||||
attrs.flags |= ATTR_TABLET;
|
||||
if (libhal_device_query_capability(hal_ctx, udi, "input.tablet_pad", NULL))
|
||||
attrs.flags |= ATTR_TABLET_PAD;
|
||||
if (libhal_device_query_capability(hal_ctx, udi, "input.touchpad", NULL))
|
||||
attrs.flags |= ATTR_TOUCHPAD;
|
||||
if (libhal_device_query_capability(hal_ctx, udi, "input.touchscreen", NULL))
|
||||
attrs.flags |= ATTR_TOUCHSCREEN;
|
||||
|
||||
parent = get_prop_string(hal_ctx, udi, "info.parent");
|
||||
if (parent) {
|
||||
int usb_vendor, usb_product;
|
||||
char *old_parent;
|
||||
|
||||
/* construct USB ID in lowercase - "0000:ffff" */
|
||||
usb_vendor = libhal_device_get_property_int(hal_ctx, parent,
|
||||
"usb.vendor_id", NULL);
|
||||
LogMessageVerb(X_INFO, 10,
|
||||
"config/hal: getting usb.vendor_id on %s "
|
||||
"returned %04x\n", parent, usb_vendor);
|
||||
usb_product = libhal_device_get_property_int(hal_ctx, parent,
|
||||
"usb.product_id", NULL);
|
||||
LogMessageVerb(X_INFO, 10,
|
||||
"config/hal: getting usb.product_id on %s "
|
||||
"returned %04x\n", parent, usb_product);
|
||||
if (usb_vendor && usb_product)
|
||||
if (asprintf(&attrs.usb_id, "%04x:%04x", usb_vendor, usb_product)
|
||||
== -1)
|
||||
attrs.usb_id = NULL;
|
||||
|
||||
attrs.pnp_id = get_prop_string(hal_ctx, parent, "pnp.id");
|
||||
old_parent = parent;
|
||||
|
||||
while (!attrs.pnp_id &&
|
||||
(parent = get_prop_string(hal_ctx, parent, "info.parent"))) {
|
||||
attrs.pnp_id = get_prop_string(hal_ctx, parent, "pnp.id");
|
||||
|
||||
free(old_parent);
|
||||
old_parent = parent;
|
||||
}
|
||||
|
||||
free(old_parent);
|
||||
}
|
||||
|
||||
input_options = input_option_new(NULL, "_source", "server/hal");
|
||||
if (!input_options) {
|
||||
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. */
|
||||
input_options = input_option_new(input_options, "path", path);
|
||||
input_options = input_option_new(input_options, "device", path);
|
||||
|
||||
input_options = input_option_new(input_options, "driver", driver);
|
||||
input_options = input_option_new(input_options, "name", name);
|
||||
|
||||
if (asprintf(&config_info, "hal:%s", udi) == -1) {
|
||||
config_info = NULL;
|
||||
LogMessage(X_ERROR, "config/hal: couldn't allocate name\n");
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
/* Check for duplicate devices */
|
||||
if (device_is_duplicate(config_info)) {
|
||||
LogMessage(X_WARNING,
|
||||
"config/hal: device %s already added. Ignoring.\n", name);
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
/* 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)) {
|
||||
char *tmp;
|
||||
|
||||
/* only support strings for all values */
|
||||
tmp_val = get_prop_string(hal_ctx, udi, psi_key);
|
||||
|
||||
if (tmp_val) {
|
||||
|
||||
/* xkb needs special handling. HAL specs include
|
||||
* input.xkb.xyz options, but the x11-input.fdi specifies
|
||||
* input.x11_options.Xkbxyz options. By default, we use
|
||||
* the former, unless the specific X11 ones are specified.
|
||||
* Since we can't predict the order in which the keys
|
||||
* arrive, we need to store them.
|
||||
*/
|
||||
if ((tmp = strcasestr(psi_key, "xkb")) && strlen(tmp) >= 4) {
|
||||
if (!strcasecmp(&tmp[3], "layout")) {
|
||||
free(xkb_opts.layout);
|
||||
xkb_opts.layout = strdup(tmp_val);
|
||||
}
|
||||
else if (!strcasecmp(&tmp[3], "model")) {
|
||||
free(xkb_opts.model);
|
||||
xkb_opts.model = strdup(tmp_val);
|
||||
}
|
||||
else if (!strcasecmp(&tmp[3], "rules")) {
|
||||
free(xkb_opts.rules);
|
||||
xkb_opts.rules = strdup(tmp_val);
|
||||
}
|
||||
else if (!strcasecmp(&tmp[3], "variant")) {
|
||||
free(xkb_opts.variant);
|
||||
xkb_opts.variant = strdup(tmp_val);
|
||||
}
|
||||
else if (!strcasecmp(&tmp[3], "options")) {
|
||||
free(xkb_opts.options);
|
||||
xkb_opts.options = strdup(tmp_val);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* all others */
|
||||
input_options =
|
||||
input_option_new(input_options,
|
||||
psi_key + sizeof(LIBHAL_PROP_KEY) -
|
||||
1, tmp_val);
|
||||
free(tmp_val);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* server 1.4 had xkb_options as strlist. */
|
||||
if ((tmp = strcasestr(psi_key, "xkb")) &&
|
||||
(strlen(tmp) >= 4) &&
|
||||
(!strcasecmp(&tmp[3], "options")) &&
|
||||
(tmp_val =
|
||||
get_prop_string_array(hal_ctx, udi, psi_key))) {
|
||||
free(xkb_opts.options);
|
||||
xkb_opts.options = strdup(tmp_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strncasecmp
|
||||
(psi_key, LIBHAL_XKB_PROP_KEY,
|
||||
sizeof(LIBHAL_XKB_PROP_KEY) - 1)) {
|
||||
char *tmp;
|
||||
|
||||
/* only support strings for all values */
|
||||
tmp_val = get_prop_string(hal_ctx, udi, psi_key);
|
||||
|
||||
if (tmp_val && strlen(psi_key) >= sizeof(LIBHAL_XKB_PROP_KEY)) {
|
||||
|
||||
tmp = &psi_key[sizeof(LIBHAL_XKB_PROP_KEY) - 1];
|
||||
|
||||
if (!strcasecmp(tmp, "layout")) {
|
||||
if (!xkb_opts.layout)
|
||||
xkb_opts.layout = strdup(tmp_val);
|
||||
}
|
||||
else if (!strcasecmp(tmp, "rules")) {
|
||||
if (!xkb_opts.rules)
|
||||
xkb_opts.rules = strdup(tmp_val);
|
||||
}
|
||||
else if (!strcasecmp(tmp, "variant")) {
|
||||
if (!xkb_opts.variant)
|
||||
xkb_opts.variant = strdup(tmp_val);
|
||||
}
|
||||
else if (!strcasecmp(tmp, "model")) {
|
||||
if (!xkb_opts.model)
|
||||
xkb_opts.model = strdup(tmp_val);
|
||||
}
|
||||
else if (!strcasecmp(tmp, "options")) {
|
||||
if (!xkb_opts.options)
|
||||
xkb_opts.options = strdup(tmp_val);
|
||||
}
|
||||
free(tmp_val);
|
||||
}
|
||||
else {
|
||||
/* server 1.4 had xkb options as strlist */
|
||||
tmp_val = get_prop_string_array(hal_ctx, udi, psi_key);
|
||||
if (tmp_val &&
|
||||
strlen(psi_key) >= sizeof(LIBHAL_XKB_PROP_KEY)) {
|
||||
tmp = &psi_key[sizeof(LIBHAL_XKB_PROP_KEY) - 1];
|
||||
if (!strcasecmp(tmp, ".options") && (!xkb_opts.options))
|
||||
xkb_opts.options = strdup(tmp_val);
|
||||
}
|
||||
free(tmp_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* psi_key doesn't need to be freed */
|
||||
libhal_psi_next(&set_iter);
|
||||
}
|
||||
|
||||
/* Now add xkb options */
|
||||
if (xkb_opts.layout)
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_layout", xkb_opts.layout);
|
||||
if (xkb_opts.rules)
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_rules", xkb_opts.rules);
|
||||
if (xkb_opts.variant)
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_variant", xkb_opts.variant);
|
||||
if (xkb_opts.model)
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_model", xkb_opts.model);
|
||||
if (xkb_opts.options)
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_options", xkb_opts.options);
|
||||
input_options = input_option_new(input_options, "config_info", config_info);
|
||||
|
||||
/* 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 ((rc = NewInputDeviceRequest(input_options, &attrs, &dev)) != Success) {
|
||||
LogMessage(X_ERROR, "config/hal: NewInputDeviceRequest failed (%d)\n",
|
||||
rc);
|
||||
dev = NULL;
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
unwind:
|
||||
if (set)
|
||||
libhal_free_property_set(set);
|
||||
free(path);
|
||||
free(driver);
|
||||
free(name);
|
||||
free(config_info);
|
||||
input_option_free_list(&input_options);
|
||||
|
||||
free(attrs.product);
|
||||
free(attrs.vendor);
|
||||
free(attrs.device);
|
||||
free(attrs.pnp_id);
|
||||
free(attrs.usb_id);
|
||||
if (attrs.tags) {
|
||||
char **tag = attrs.tags;
|
||||
|
||||
while (*tag) {
|
||||
free(*tag);
|
||||
tag++;
|
||||
}
|
||||
free(attrs.tags);
|
||||
}
|
||||
|
||||
free(xkb_opts.layout);
|
||||
free(xkb_opts.rules);
|
||||
free(xkb_opts.model);
|
||||
free(xkb_opts.variant);
|
||||
free(xkb_opts.options);
|
||||
|
||||
dbus_error_free(&error);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
disconnect_hook(void *data)
|
||||
{
|
||||
DBusError error;
|
||||
struct config_hal_info *info = data;
|
||||
|
||||
if (info->hal_ctx) {
|
||||
if (dbus_connection_get_is_connected(info->system_bus)) {
|
||||
dbus_error_init(&error);
|
||||
if (!libhal_ctx_shutdown(info->hal_ctx, &error))
|
||||
LogMessage(X_WARNING,
|
||||
"config/hal: disconnect_hook couldn't shut down context: %s (%s)\n",
|
||||
error.name, error.message);
|
||||
dbus_error_free(&error);
|
||||
}
|
||||
libhal_ctx_free(info->hal_ctx);
|
||||
}
|
||||
|
||||
info->hal_ctx = NULL;
|
||||
info->system_bus = NULL;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
connect_and_register(DBusConnection * connection, struct config_hal_info *info)
|
||||
{
|
||||
DBusError error;
|
||||
char **devices;
|
||||
int num_devices, i;
|
||||
|
||||
if (info->hal_ctx)
|
||||
return TRUE; /* already registered, pretend we did something */
|
||||
|
||||
info->system_bus = connection;
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
info->hal_ctx = libhal_ctx_new();
|
||||
if (!info->hal_ctx) {
|
||||
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)) {
|
||||
LogMessage(X_ERROR,
|
||||
"config/hal: couldn't associate HAL context with bus\n");
|
||||
goto out_err;
|
||||
}
|
||||
if (!libhal_ctx_init(info->hal_ctx, &error)) {
|
||||
LogMessage(X_ERROR,
|
||||
"config/hal: couldn't initialise context: %s (%s)\n",
|
||||
error.name ? error.name : "unknown error",
|
||||
error.message ? error.message : "null");
|
||||
goto out_err;
|
||||
}
|
||||
if (!libhal_device_property_watch_all(info->hal_ctx, &error)) {
|
||||
LogMessage(X_ERROR,
|
||||
"config/hal: couldn't watch all properties: %s (%s)\n",
|
||||
error.name ? error.name : "unknown error",
|
||||
error.message ? error.message : "null");
|
||||
goto out_ctx;
|
||||
}
|
||||
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);
|
||||
/* FIXME: Get default devices if error is set. */
|
||||
if (dbus_error_is_set(&error)) {
|
||||
LogMessage(X_ERROR, "config/hal: couldn't find input device: %s (%s)\n",
|
||||
error.name ? error.name : "unknown error",
|
||||
error.message ? error.message : "null");
|
||||
goto out_ctx;
|
||||
}
|
||||
for (i = 0; i < num_devices; i++)
|
||||
device_added(info->hal_ctx, devices[i]);
|
||||
libhal_free_string_array(devices);
|
||||
|
||||
dbus_error_free(&error);
|
||||
|
||||
return TRUE;
|
||||
|
||||
out_ctx:
|
||||
dbus_error_free(&error);
|
||||
|
||||
if (!libhal_ctx_shutdown(info->hal_ctx, &error)) {
|
||||
LogMessage(X_WARNING,
|
||||
"config/hal: couldn't shut down context: %s (%s)\n",
|
||||
error.name ? error.name : "unknown error",
|
||||
error.message ? error.message : "null");
|
||||
dbus_error_free(&error);
|
||||
}
|
||||
|
||||
out_err:
|
||||
dbus_error_free(&error);
|
||||
|
||||
if (info->hal_ctx) {
|
||||
libhal_ctx_free(info->hal_ctx);
|
||||
}
|
||||
|
||||
info->hal_ctx = NULL;
|
||||
info->system_bus = NULL;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle NewOwnerChanged signals to deal with HAL startup at X server runtime.
|
||||
*
|
||||
* NewOwnerChanged is send once when HAL shuts down, and once again when it
|
||||
* comes back up. Message has three arguments, first is the name
|
||||
* (org.freedesktop.Hal), the second one is the old owner, third one is new
|
||||
* owner.
|
||||
*/
|
||||
static DBusHandlerResult
|
||||
ownerchanged_handler(DBusConnection * connection, DBusMessage * message,
|
||||
void *data)
|
||||
{
|
||||
int ret = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
|
||||
if (dbus_message_is_signal(message,
|
||||
"org.freedesktop.DBus", "NameOwnerChanged")) {
|
||||
DBusError error;
|
||||
char *name, *old_owner, *new_owner;
|
||||
|
||||
dbus_error_init(&error);
|
||||
dbus_message_get_args(message, &error,
|
||||
DBUS_TYPE_STRING, &name,
|
||||
DBUS_TYPE_STRING, &old_owner,
|
||||
DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID);
|
||||
|
||||
if (dbus_error_is_set(&error)) {
|
||||
ErrorF
|
||||
("[config/hal] failed to get NameOwnerChanged args: %s (%s)\n",
|
||||
error.name, error.message);
|
||||
}
|
||||
else if (name && strcmp(name, "org.freedesktop.Hal") == 0) {
|
||||
|
||||
if (!old_owner || !strlen(old_owner)) {
|
||||
DebugF("[config/hal] HAL startup detected.\n");
|
||||
if (connect_and_register
|
||||
(connection, (struct config_hal_info *) data))
|
||||
dbus_connection_unregister_object_path(connection,
|
||||
"/org/freedesktop/DBus");
|
||||
else
|
||||
ErrorF("[config/hal] Failed to connect to HAL bus.\n");
|
||||
}
|
||||
|
||||
ret = DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
dbus_error_free(&error);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a handler for the NameOwnerChanged signal.
|
||||
*/
|
||||
static BOOL
|
||||
listen_for_startup(DBusConnection * connection, void *data)
|
||||
{
|
||||
DBusObjectPathVTable vtable = {.message_function = ownerchanged_handler, };
|
||||
DBusError error;
|
||||
const char MATCH_RULE[] = "sender='org.freedesktop.DBus',"
|
||||
"interface='org.freedesktop.DBus',"
|
||||
"type='signal',"
|
||||
"path='/org/freedesktop/DBus'," "member='NameOwnerChanged'";
|
||||
int rc = FALSE;
|
||||
|
||||
dbus_error_init(&error);
|
||||
dbus_bus_add_match(connection, MATCH_RULE, &error);
|
||||
if (!dbus_error_is_set(&error)) {
|
||||
if (dbus_connection_register_object_path(connection,
|
||||
"/org/freedesktop/DBus",
|
||||
&vtable, data))
|
||||
rc = TRUE;
|
||||
else
|
||||
ErrorF("[config/hal] cannot register object path.\n");
|
||||
}
|
||||
else {
|
||||
ErrorF("[config/hal] couldn't add match rule: %s (%s)\n", error.name,
|
||||
error.message);
|
||||
ErrorF("[config/hal] cannot detect a HAL startup.\n");
|
||||
}
|
||||
|
||||
dbus_error_free(&error);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
connect_hook(DBusConnection * connection, void *data)
|
||||
{
|
||||
struct config_hal_info *info = data;
|
||||
|
||||
if (listen_for_startup(connection, data) &&
|
||||
connect_and_register(connection, info))
|
||||
dbus_connection_unregister_object_path(connection,
|
||||
"/org/freedesktop/DBus");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static struct config_hal_info hal_info;
|
||||
|
||||
static struct 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 (!dbus_core_add_hook(&hook)) {
|
||||
LogMessage(X_ERROR, "config/hal: failed to add D-Bus hook\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* verbose message */
|
||||
LogMessageVerb(X_INFO, 7, "config/hal: initialized\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
config_hal_fini(void)
|
||||
{
|
||||
dbus_core_remove_hook(&hook);
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
srcs_config = [
|
||||
'config.c',
|
||||
]
|
||||
|
||||
config_dep = [common_dep]
|
||||
|
||||
if build_dbus
|
||||
srcs_config += 'dbus-core.c'
|
||||
config_dep += dbus_dep
|
||||
endif
|
||||
|
||||
if build_hal
|
||||
srcs_config += 'hal.c'
|
||||
config_dep += hal_dep
|
||||
endif
|
||||
|
||||
if build_udev
|
||||
srcs_config += 'udev.c'
|
||||
config_dep += udev_dep
|
||||
endif
|
||||
|
||||
if host_machine.system() == 'openbsd'
|
||||
srcs_config += 'wscons.c'
|
||||
endif
|
579
config/udev.c
579
config/udev.c
|
@ -1,579 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2009 Julien Cristau
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Author: Julien Cristau <jcristau@debian.org>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <libudev.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "input.h"
|
||||
#include "inputstr.h"
|
||||
#include "hotplug.h"
|
||||
#include "config-backends.h"
|
||||
#include "os.h"
|
||||
#include "globals.h"
|
||||
#include "systemd-logind.h"
|
||||
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#define UDEV_XKB_PROP_KEY "xkb"
|
||||
|
||||
#define LOG_PROPERTY(path, prop, val) \
|
||||
LogMessageVerb(X_INFO, 10, \
|
||||
"config/udev: getting property %s on %s " \
|
||||
"returned \"%s\"\n", \
|
||||
(prop), (path), (val) ? (val) : "(null)")
|
||||
#define LOG_SYSATTR(path, attr, val) \
|
||||
LogMessageVerb(X_INFO, 10, \
|
||||
"config/udev: getting attribute %s on %s " \
|
||||
"returned \"%s\"\n", \
|
||||
(attr), (path), (val) ? (val) : "(null)")
|
||||
|
||||
static struct udev_monitor *udev_monitor;
|
||||
|
||||
#ifdef CONFIG_UDEV_KMS
|
||||
static void
|
||||
config_udev_odev_setup_attribs(struct udev_device *udev_device, const char *path, const char *syspath,
|
||||
int major, int minor,
|
||||
config_odev_probe_proc_ptr probe_callback);
|
||||
#endif
|
||||
|
||||
static char itoa_buf[16];
|
||||
|
||||
static const char *itoa(int i)
|
||||
{
|
||||
snprintf(itoa_buf, sizeof(itoa_buf), "%d", i);
|
||||
return itoa_buf;
|
||||
}
|
||||
|
||||
static Bool
|
||||
check_seat(struct udev_device *udev_device)
|
||||
{
|
||||
const char *dev_seat;
|
||||
|
||||
dev_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
|
||||
if (!dev_seat)
|
||||
dev_seat = "seat0";
|
||||
|
||||
if (SeatId && strcmp(dev_seat, SeatId))
|
||||
return FALSE;
|
||||
|
||||
if (!SeatId && strcmp(dev_seat, "seat0"))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
device_added(struct udev_device *udev_device)
|
||||
{
|
||||
const char *path, *name = NULL;
|
||||
char *config_info = NULL;
|
||||
const char *syspath;
|
||||
const char *tags_prop;
|
||||
const char *key, *value, *tmp;
|
||||
#ifdef CONFIG_UDEV_KMS
|
||||
const char *subsys = NULL;
|
||||
#endif
|
||||
InputOption *input_options;
|
||||
InputAttributes attrs = { };
|
||||
DeviceIntPtr dev = NULL;
|
||||
struct udev_list_entry *set, *entry;
|
||||
struct udev_device *parent;
|
||||
int rc;
|
||||
dev_t devnum;
|
||||
|
||||
path = udev_device_get_devnode(udev_device);
|
||||
|
||||
syspath = udev_device_get_syspath(udev_device);
|
||||
|
||||
if (!path || !syspath)
|
||||
return;
|
||||
|
||||
if (!check_seat(udev_device))
|
||||
return;
|
||||
|
||||
devnum = udev_device_get_devnum(udev_device);
|
||||
|
||||
#ifdef CONFIG_UDEV_KMS
|
||||
subsys = udev_device_get_subsystem(udev_device);
|
||||
|
||||
if (subsys && !strcmp(subsys, "drm")) {
|
||||
const char *sysname = udev_device_get_sysname(udev_device);
|
||||
|
||||
if (strncmp(sysname, "card", 4) != 0)
|
||||
return;
|
||||
|
||||
/* Check for devices already added through xf86platformProbe() */
|
||||
if (xf86_find_platform_device_by_devnum(major(devnum), minor(devnum)))
|
||||
return;
|
||||
|
||||
LogMessage(X_INFO, "config/udev: Adding drm device (%s)\n", path);
|
||||
|
||||
config_udev_odev_setup_attribs(udev_device, path, syspath, major(devnum),
|
||||
minor(devnum), NewGPUDeviceRequest);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
value = udev_device_get_property_value(udev_device, "ID_INPUT");
|
||||
if (!value || !strcmp(value, "0")) {
|
||||
LogMessageVerb(X_INFO, 10,
|
||||
"config/udev: ignoring device %s without "
|
||||
"property ID_INPUT set\n", path);
|
||||
return;
|
||||
}
|
||||
|
||||
input_options = input_option_new(NULL, "_source", "server/udev");
|
||||
if (!input_options)
|
||||
return;
|
||||
|
||||
parent = udev_device_get_parent(udev_device);
|
||||
if (parent) {
|
||||
const char *ppath = udev_device_get_devnode(parent);
|
||||
const char *product = udev_device_get_property_value(parent, "PRODUCT");
|
||||
const char *pnp_id = udev_device_get_sysattr_value(parent, "id");
|
||||
unsigned int usb_vendor, usb_model;
|
||||
|
||||
name = udev_device_get_sysattr_value(parent, "name");
|
||||
LOG_SYSATTR(ppath, "name", name);
|
||||
if (!name) {
|
||||
name = udev_device_get_property_value(parent, "NAME");
|
||||
LOG_PROPERTY(ppath, "NAME", name);
|
||||
}
|
||||
|
||||
/* construct USB ID in lowercase hex - "0000:ffff" */
|
||||
if (product &&
|
||||
sscanf(product, "%*x/%4x/%4x/%*x", &usb_vendor, &usb_model) == 2) {
|
||||
char *usb_id;
|
||||
if (asprintf(&usb_id, "%04x:%04x", usb_vendor, usb_model)
|
||||
== -1)
|
||||
usb_id = NULL;
|
||||
else
|
||||
LOG_PROPERTY(ppath, "PRODUCT", product);
|
||||
attrs.usb_id = usb_id;
|
||||
}
|
||||
|
||||
while (!pnp_id && (parent = udev_device_get_parent(parent))) {
|
||||
pnp_id = udev_device_get_sysattr_value(parent, "id");
|
||||
if (!pnp_id)
|
||||
continue;
|
||||
|
||||
attrs.pnp_id = strdup(pnp_id);
|
||||
ppath = udev_device_get_devnode(parent);
|
||||
LOG_SYSATTR(ppath, "id", pnp_id);
|
||||
}
|
||||
|
||||
}
|
||||
if (!name)
|
||||
name = "(unnamed)";
|
||||
else
|
||||
attrs.product = strdup(name);
|
||||
input_options = input_option_new(input_options, "name", name);
|
||||
input_options = input_option_new(input_options, "path", path);
|
||||
input_options = input_option_new(input_options, "device", path);
|
||||
input_options = input_option_new(input_options, "major", itoa(major(devnum)));
|
||||
input_options = input_option_new(input_options, "minor", itoa(minor(devnum)));
|
||||
if (path)
|
||||
attrs.device = strdup(path);
|
||||
|
||||
tags_prop = udev_device_get_property_value(udev_device, "ID_INPUT.tags");
|
||||
LOG_PROPERTY(path, "ID_INPUT.tags", tags_prop);
|
||||
attrs.tags = xstrtokenize(tags_prop, ",");
|
||||
|
||||
if (asprintf(&config_info, "udev:%s", syspath) == -1) {
|
||||
config_info = NULL;
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
if (device_is_duplicate(config_info)) {
|
||||
LogMessage(X_WARNING, "config/udev: device %s already added. "
|
||||
"Ignoring.\n", name);
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
set = udev_device_get_properties_list_entry(udev_device);
|
||||
udev_list_entry_foreach(entry, set) {
|
||||
key = udev_list_entry_get_name(entry);
|
||||
if (!key)
|
||||
continue;
|
||||
value = udev_list_entry_get_value(entry);
|
||||
if (!strncasecmp(key, UDEV_XKB_PROP_KEY, sizeof(UDEV_XKB_PROP_KEY) - 1)) {
|
||||
LOG_PROPERTY(path, key, value);
|
||||
tmp = key + sizeof(UDEV_XKB_PROP_KEY) - 1;
|
||||
if (!strcasecmp(tmp, "rules"))
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_rules", value);
|
||||
else if (!strcasecmp(tmp, "layout"))
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_layout", value);
|
||||
else if (!strcasecmp(tmp, "variant"))
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_variant", value);
|
||||
else if (!strcasecmp(tmp, "model"))
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_model", value);
|
||||
else if (!strcasecmp(tmp, "options"))
|
||||
input_options =
|
||||
input_option_new(input_options, "xkb_options", value);
|
||||
}
|
||||
else if (!strcmp(key, "ID_VENDOR")) {
|
||||
LOG_PROPERTY(path, key, value);
|
||||
attrs.vendor = strdup(value);
|
||||
} else if (!strncmp(key, "ID_INPUT_", 9)) {
|
||||
const struct pfmap {
|
||||
const char *property;
|
||||
unsigned int flag;
|
||||
} map[] = {
|
||||
{ "ID_INPUT_KEY", ATTR_KEY },
|
||||
{ "ID_INPUT_KEYBOARD", ATTR_KEYBOARD },
|
||||
{ "ID_INPUT_MOUSE", ATTR_POINTER },
|
||||
{ "ID_INPUT_JOYSTICK", ATTR_JOYSTICK },
|
||||
{ "ID_INPUT_TABLET", ATTR_TABLET },
|
||||
{ "ID_INPUT_TABLET_PAD", ATTR_TABLET_PAD },
|
||||
{ "ID_INPUT_TOUCHPAD", ATTR_TOUCHPAD },
|
||||
{ "ID_INPUT_TOUCHSCREEN", ATTR_TOUCHSCREEN },
|
||||
{ NULL, 0 },
|
||||
};
|
||||
|
||||
/* Anything but the literal string "0" is considered a
|
||||
* boolean true. The empty string isn't a thing with udev
|
||||
* properties anyway */
|
||||
if (value && strcmp(value, "0")) {
|
||||
const struct pfmap *m = map;
|
||||
|
||||
while (m->property != NULL) {
|
||||
if (!strcmp(m->property, key)) {
|
||||
LOG_PROPERTY(path, key, value);
|
||||
attrs.flags |= m->flag;
|
||||
}
|
||||
m++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input_options = input_option_new(input_options, "config_info", config_info);
|
||||
|
||||
/* Default setting needed for non-seat0 seats */
|
||||
if (ServerIsNotSeat0())
|
||||
input_options = input_option_new(input_options, "GrabDevice", "on");
|
||||
|
||||
LogMessage(X_INFO, "config/udev: Adding input device %s (%s)\n",
|
||||
name, path);
|
||||
rc = NewInputDeviceRequest(input_options, &attrs, &dev);
|
||||
if (rc != Success)
|
||||
goto unwind;
|
||||
|
||||
unwind:
|
||||
free(config_info);
|
||||
input_option_free_list(&input_options);
|
||||
|
||||
free(attrs.usb_id);
|
||||
free(attrs.pnp_id);
|
||||
free(attrs.product);
|
||||
free(attrs.device);
|
||||
free(attrs.vendor);
|
||||
if (attrs.tags) {
|
||||
char **tag = attrs.tags;
|
||||
|
||||
while (*tag) {
|
||||
free(*tag);
|
||||
tag++;
|
||||
}
|
||||
free(attrs.tags);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
device_removed(struct udev_device *device)
|
||||
{
|
||||
char *value;
|
||||
const char *syspath = udev_device_get_syspath(device);
|
||||
|
||||
#ifdef CONFIG_UDEV_KMS
|
||||
const char *subsys = udev_device_get_subsystem(device);
|
||||
|
||||
if (subsys && !strcmp(subsys, "drm")) {
|
||||
const char *sysname = udev_device_get_sysname(device);
|
||||
const char *path = udev_device_get_devnode(device);
|
||||
dev_t devnum = udev_device_get_devnum(device);
|
||||
|
||||
if ((strncmp(sysname,"card", 4) != 0) || (path == NULL))
|
||||
return;
|
||||
|
||||
LogMessage(X_INFO, "config/udev: removing GPU device %s %s\n",
|
||||
syspath, path);
|
||||
config_udev_odev_setup_attribs(device, path, syspath, major(devnum),
|
||||
minor(devnum), DeleteGPUDeviceRequest);
|
||||
/* Retry vtenter after a drm node removal */
|
||||
systemd_logind_vtenter();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (asprintf(&value, "udev:%s", syspath) == -1)
|
||||
return;
|
||||
|
||||
remove_devices("udev", value);
|
||||
|
||||
free(value);
|
||||
}
|
||||
|
||||
static void
|
||||
socket_handler(int fd, int ready, void *data)
|
||||
{
|
||||
struct udev_device *udev_device;
|
||||
const char *action;
|
||||
|
||||
input_lock();
|
||||
udev_device = udev_monitor_receive_device(udev_monitor);
|
||||
if (!udev_device) {
|
||||
input_unlock();
|
||||
return;
|
||||
}
|
||||
action = udev_device_get_action(udev_device);
|
||||
if (action) {
|
||||
if (!strcmp(action, "add")) {
|
||||
device_removed(udev_device);
|
||||
device_added(udev_device);
|
||||
} else if (!strcmp(action, "change")) {
|
||||
/* ignore change for the drm devices */
|
||||
const char *subsys = udev_device_get_subsystem(udev_device);
|
||||
|
||||
if (subsys && strcmp(subsys, "drm")) {
|
||||
device_removed(udev_device);
|
||||
device_added(udev_device);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(action, "remove"))
|
||||
device_removed(udev_device);
|
||||
}
|
||||
udev_device_unref(udev_device);
|
||||
input_unlock();
|
||||
}
|
||||
|
||||
int
|
||||
config_udev_pre_init(void)
|
||||
{
|
||||
struct udev *udev;
|
||||
|
||||
udev = udev_new();
|
||||
if (!udev)
|
||||
return 0;
|
||||
|
||||
udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
|
||||
if (!udev_monitor)
|
||||
return 0;
|
||||
|
||||
udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "input",
|
||||
NULL);
|
||||
/* For Wacom serial devices */
|
||||
udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL);
|
||||
#ifdef CONFIG_UDEV_KMS
|
||||
/* For output GPU devices */
|
||||
udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "drm", NULL);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UDEV_MONITOR_FILTER_ADD_MATCH_TAG
|
||||
if (ServerIsNotSeat0())
|
||||
udev_monitor_filter_add_match_tag(udev_monitor, SeatId);
|
||||
#endif
|
||||
if (udev_monitor_enable_receiving(udev_monitor)) {
|
||||
ErrorF("config/udev: failed to bind the udev monitor\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
config_udev_init(void)
|
||||
{
|
||||
struct udev *udev;
|
||||
struct udev_enumerate *enumerate;
|
||||
struct udev_list_entry *devices, *device;
|
||||
|
||||
udev = udev_monitor_get_udev(udev_monitor);
|
||||
enumerate = udev_enumerate_new(udev);
|
||||
if (!enumerate)
|
||||
return 0;
|
||||
|
||||
udev_enumerate_add_match_subsystem(enumerate, "input");
|
||||
udev_enumerate_add_match_subsystem(enumerate, "tty");
|
||||
#ifdef CONFIG_UDEV_KMS
|
||||
udev_enumerate_add_match_subsystem(enumerate, "drm");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UDEV_ENUMERATE_ADD_MATCH_TAG
|
||||
if (ServerIsNotSeat0())
|
||||
udev_enumerate_add_match_tag(enumerate, SeatId);
|
||||
#endif
|
||||
|
||||
udev_enumerate_scan_devices(enumerate);
|
||||
devices = udev_enumerate_get_list_entry(enumerate);
|
||||
udev_list_entry_foreach(device, devices) {
|
||||
const char *syspath = udev_list_entry_get_name(device);
|
||||
struct udev_device *udev_device =
|
||||
udev_device_new_from_syspath(udev, syspath);
|
||||
|
||||
/* Device might be gone by the time we try to open it */
|
||||
if (!udev_device)
|
||||
continue;
|
||||
|
||||
device_added(udev_device);
|
||||
udev_device_unref(udev_device);
|
||||
}
|
||||
udev_enumerate_unref(enumerate);
|
||||
|
||||
SetNotifyFd(udev_monitor_get_fd(udev_monitor), socket_handler, X_NOTIFY_READ, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
config_udev_fini(void)
|
||||
{
|
||||
struct udev *udev;
|
||||
|
||||
if (!udev_monitor)
|
||||
return;
|
||||
|
||||
udev = udev_monitor_get_udev(udev_monitor);
|
||||
|
||||
RemoveNotifyFd(udev_monitor_get_fd(udev_monitor));
|
||||
udev_monitor_unref(udev_monitor);
|
||||
udev_monitor = NULL;
|
||||
udev_unref(udev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UDEV_KMS
|
||||
|
||||
/* Find the last occurrence of the needle in haystack */
|
||||
static char *strrstr(const char *haystack, const char *needle)
|
||||
{
|
||||
char *prev, *last, *tmp;
|
||||
|
||||
prev = strstr(haystack, needle);
|
||||
if (!prev)
|
||||
return NULL;
|
||||
|
||||
last = prev;
|
||||
tmp = prev + 1;
|
||||
|
||||
while (tmp) {
|
||||
last = strstr(tmp, needle);
|
||||
if (!last)
|
||||
return prev;
|
||||
else {
|
||||
prev = last;
|
||||
tmp = prev + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
static void
|
||||
config_udev_odev_setup_attribs(struct udev_device *udev_device, const char *path, const char *syspath,
|
||||
int major, int minor,
|
||||
config_odev_probe_proc_ptr probe_callback)
|
||||
{
|
||||
struct OdevAttributes *attribs = config_odev_allocate_attributes();
|
||||
const char *value, *str;
|
||||
|
||||
attribs->path = XNFstrdup(path);
|
||||
attribs->syspath = XNFstrdup(syspath);
|
||||
attribs->major = major;
|
||||
attribs->minor = minor;
|
||||
|
||||
value = udev_device_get_property_value(udev_device, "ID_PATH");
|
||||
if (value && (str = strrstr(value, "pci-"))) {
|
||||
value = str;
|
||||
|
||||
if ((str = strstr(value, "usb-")))
|
||||
value = str;
|
||||
|
||||
attribs->busid = XNFstrdup(value);
|
||||
attribs->busid[3] = ':';
|
||||
}
|
||||
|
||||
/* ownership of attribs is passed to probe layer */
|
||||
probe_callback(attribs);
|
||||
}
|
||||
|
||||
void
|
||||
config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback)
|
||||
{
|
||||
struct udev *udev;
|
||||
struct udev_enumerate *enumerate;
|
||||
struct udev_list_entry *devices, *device;
|
||||
|
||||
udev = udev_monitor_get_udev(udev_monitor);
|
||||
enumerate = udev_enumerate_new(udev);
|
||||
if (!enumerate)
|
||||
return;
|
||||
|
||||
udev_enumerate_add_match_subsystem(enumerate, "drm");
|
||||
udev_enumerate_add_match_sysname(enumerate, "card[0-9]*");
|
||||
#ifdef HAVE_UDEV_ENUMERATE_ADD_MATCH_TAG
|
||||
if (ServerIsNotSeat0())
|
||||
udev_enumerate_add_match_tag(enumerate, SeatId);
|
||||
#endif
|
||||
udev_enumerate_scan_devices(enumerate);
|
||||
devices = udev_enumerate_get_list_entry(enumerate);
|
||||
udev_list_entry_foreach(device, devices) {
|
||||
const char *syspath = udev_list_entry_get_name(device);
|
||||
struct udev_device *udev_device = udev_device_new_from_syspath(udev, syspath);
|
||||
const char *path = udev_device_get_devnode(udev_device);
|
||||
const char *sysname = udev_device_get_sysname(udev_device);
|
||||
dev_t devnum = udev_device_get_devnum(udev_device);
|
||||
const char *subsys = udev_device_get_subsystem(udev_device);
|
||||
|
||||
if (!path || !syspath || !subsys)
|
||||
goto no_probe;
|
||||
else if (strcmp(subsys, "drm") != 0)
|
||||
goto no_probe;
|
||||
else if (strncmp(sysname, "card", 4) != 0)
|
||||
goto no_probe;
|
||||
else if (!check_seat(udev_device))
|
||||
goto no_probe;
|
||||
|
||||
config_udev_odev_setup_attribs(udev_device, path, syspath, major(devnum),
|
||||
minor(devnum), probe_callback);
|
||||
no_probe:
|
||||
udev_device_unref(udev_device);
|
||||
}
|
||||
udev_enumerate_unref(enumerate);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
262
config/wscons.c
262
config/wscons.c
|
@ -1,262 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2011 Matthieu Herrb
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <dev/wscons/wsconsio.h>
|
||||
#include <dev/wscons/wsksymdef.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "input.h"
|
||||
#include "inputstr.h"
|
||||
#include "os.h"
|
||||
#include "config-backends.h"
|
||||
|
||||
#define WSCONS_KBD_DEVICE "/dev/wskbd"
|
||||
#define WSCONS_MOUSE_PREFIX "/dev/wsmouse"
|
||||
|
||||
#define KB_OVRENC \
|
||||
{ KB_UK, "gb" }, \
|
||||
{ KB_SV, "se" }, \
|
||||
{ KB_SG, "ch" }, \
|
||||
{ KB_SF, "ch" }, \
|
||||
{ KB_LA, "latam" }, \
|
||||
{ KB_CF, "ca" }
|
||||
|
||||
struct nameint {
|
||||
int val;
|
||||
char *name;
|
||||
} kbdenc[] = {
|
||||
KB_OVRENC,
|
||||
KB_ENCTAB,
|
||||
{0}
|
||||
};
|
||||
|
||||
struct nameint kbdvar[] = {
|
||||
{KB_NODEAD | KB_SG, "de_nodeadkeys"},
|
||||
{KB_NODEAD | KB_SF, "fr_nodeadkeys"},
|
||||
{KB_SF, "fr"},
|
||||
{KB_DVORAK | KB_CF, "fr-dvorak"},
|
||||
{KB_DVORAK | KB_FR, "bepo"},
|
||||
{KB_DVORAK, "dvorak"},
|
||||
{KB_CF, "fr-legacy"},
|
||||
{KB_NODEAD, "nodeadkeys"},
|
||||
{0}
|
||||
};
|
||||
|
||||
struct nameint kbdopt[] = {
|
||||
{KB_SWAPCTRLCAPS, "ctrl:swapcaps"},
|
||||
{0}
|
||||
};
|
||||
|
||||
struct nameint kbdmodel[] = {
|
||||
{WSKBD_TYPE_ZAURUS, "zaurus"},
|
||||
{0}
|
||||
};
|
||||
|
||||
static void
|
||||
wscons_add_keyboard(void)
|
||||
{
|
||||
InputAttributes attrs = { };
|
||||
DeviceIntPtr dev = NULL;
|
||||
InputOption *input_options = NULL;
|
||||
char *config_info = NULL;
|
||||
int fd, i, rc;
|
||||
unsigned int type;
|
||||
kbd_t wsenc = 0;
|
||||
|
||||
/* Find keyboard configuration */
|
||||
fd = open(WSCONS_KBD_DEVICE, O_RDWR | O_NONBLOCK | O_EXCL);
|
||||
if (fd == -1) {
|
||||
LogMessage(X_ERROR, "wskbd: open %s: %s\n",
|
||||
WSCONS_KBD_DEVICE, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (ioctl(fd, WSKBDIO_GETENCODING, &wsenc) == -1) {
|
||||
LogMessage(X_WARNING, "wskbd: ioctl(WSKBDIO_GETENCODING) "
|
||||
"failed: %s\n", strerror(errno));
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
if (ioctl(fd, WSKBDIO_GTYPE, &type) == -1) {
|
||||
LogMessage(X_WARNING, "wskbd: ioctl(WSKBDIO_GTYPE) "
|
||||
"failed: %s\n", strerror(errno));
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
input_options = input_option_new(input_options, "_source", "server/wscons");
|
||||
if (input_options == NULL)
|
||||
return;
|
||||
|
||||
LogMessage(X_INFO, "config/wscons: checking input device %s\n",
|
||||
WSCONS_KBD_DEVICE);
|
||||
input_options = input_option_new(input_options, "name", WSCONS_KBD_DEVICE);
|
||||
input_options = input_option_new(input_options, "driver", "kbd");
|
||||
|
||||
config_info = Xprintf("wscons:%s", WSCONS_KBD_DEVICE);
|
||||
if (!config_info)
|
||||
goto unwind;
|
||||
if (KB_ENCODING(wsenc) == KB_USER) {
|
||||
/* Ignore wscons "user" layout */
|
||||
LogMessageVerb(X_INFO, 3, "wskbd: ignoring \"user\" layout\n");
|
||||
goto kbd_config_done;
|
||||
}
|
||||
for (i = 0; kbdenc[i].val; i++)
|
||||
if (KB_ENCODING(wsenc) == kbdenc[i].val) {
|
||||
LogMessageVerb(X_INFO, 3, "wskbd: using layout %s\n",
|
||||
kbdenc[i].name);
|
||||
input_options = input_option_new(input_options,
|
||||
"xkb_layout", kbdenc[i].name);
|
||||
break;
|
||||
}
|
||||
for (i = 0; kbdvar[i].val; i++)
|
||||
if (wsenc == kbdvar[i].val || KB_VARIANT(wsenc) == kbdvar[i].val) {
|
||||
LogMessageVerb(X_INFO, 3, "wskbd: using variant %s\n",
|
||||
kbdvar[i].name);
|
||||
input_options = input_option_new(input_options,
|
||||
"xkb_variant", kbdvar[i].name);
|
||||
break;
|
||||
}
|
||||
for (i = 0; kbdopt[i].val; i++)
|
||||
if (KB_VARIANT(wsenc) == kbdopt[i].val) {
|
||||
LogMessageVerb(X_INFO, 3, "wskbd: using option %s\n",
|
||||
kbdopt[i].name);
|
||||
input_options = input_option_new(input_options,
|
||||
"xkb_options", kbdopt[i].name);
|
||||
break;
|
||||
}
|
||||
for (i = 0; kbdmodel[i].val; i++)
|
||||
if (type == kbdmodel[i].val) {
|
||||
LogMessageVerb(X_INFO, 3, "wskbd: using model %s\n",
|
||||
kbdmodel[i].name);
|
||||
input_options = input_option_new(input_options,
|
||||
"xkb_model", kbdmodel[i].name);
|
||||
break;
|
||||
}
|
||||
|
||||
kbd_config_done:
|
||||
attrs.flags |= ATTR_KEY | ATTR_KEYBOARD;
|
||||
rc = NewInputDeviceRequest(input_options, &attrs, &dev);
|
||||
if (rc != Success)
|
||||
goto unwind;
|
||||
|
||||
for (; dev; dev = dev->next) {
|
||||
free(dev->config_info);
|
||||
dev->config_info = strdup(config_info);
|
||||
}
|
||||
unwind:
|
||||
input_option_free_list(&input_options);
|
||||
}
|
||||
|
||||
static void
|
||||
wscons_add_pointer(const char *path, const char *driver, int flags)
|
||||
{
|
||||
InputAttributes attrs = { };
|
||||
DeviceIntPtr dev = NULL;
|
||||
InputOption *input_options = NULL;
|
||||
char *config_info = NULL;
|
||||
int rc;
|
||||
|
||||
config_info = Xprintf("wscons:%s", path);
|
||||
if (!config_info)
|
||||
return;
|
||||
|
||||
input_options = input_option_new(input_options, "_source", "server/wscons");
|
||||
if (input_options == NULL)
|
||||
return;
|
||||
|
||||
input_options = input_option_new(input_options, "name", strdup(path));
|
||||
input_options = input_option_new(input_options, "driver", strdup(driver));
|
||||
input_options = input_option_new(input_options, "device", strdup(path));
|
||||
LogMessage(X_INFO, "config/wscons: checking input device %s\n", path);
|
||||
attrs.flags |= flags;
|
||||
rc = NewInputDeviceRequest(input_options, &attrs, &dev);
|
||||
if (rc != Success)
|
||||
goto unwind;
|
||||
|
||||
for (; dev; dev = dev->next) {
|
||||
free(dev->config_info);
|
||||
dev->config_info = strdup(config_info);
|
||||
}
|
||||
unwind:
|
||||
input_option_free_list(&input_options);
|
||||
}
|
||||
|
||||
static void
|
||||
wscons_add_pointers(void)
|
||||
{
|
||||
char devname[256];
|
||||
int fd, i, wsmouse_type;
|
||||
|
||||
/* Check pointing devices */
|
||||
for (i = 0; i < 4; i++) {
|
||||
snprintf(devname, sizeof(devname), "%s%d", WSCONS_MOUSE_PREFIX, i);
|
||||
LogMessageVerb(X_INFO, 10, "wsmouse: checking %s\n", devname);
|
||||
fd = open_device(devnamem O_RDWR | O_NONBLOCK | O_EXCL);
|
||||
if (fd == -1) {
|
||||
LogMessageVerb(X_WARNING, 10, "%s: %s\n", devname, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
if (ioctl(fd, WSMOUSEIO_GTYPE, &wsmouse_type) != 0) {
|
||||
LogMessageVerb(X_WARNING, 10,
|
||||
"%s: WSMOUSEIO_GTYPE failed\n", devname);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
close(fd);
|
||||
switch (wsmouse_type) {
|
||||
case WSMOUSE_TYPE_SYNAPTICS:
|
||||
wscons_add_pointer(devname, "synaptics", ATTR_TOUCHPAD);
|
||||
break;
|
||||
case WSMOUSE_TYPE_TPANEL:
|
||||
wscons_add_pointer(devname, "ws", ATTR_TOUCHSCREEN);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Add a default entry catching all other mux elements as "mouse" */
|
||||
wscons_add_pointer(WSCONS_MOUSE_PREFIX, "mouse", ATTR_POINTER);
|
||||
}
|
||||
|
||||
int
|
||||
config_wscons_init(void)
|
||||
{
|
||||
wscons_add_keyboard();
|
||||
wscons_add_pointers();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
config_wscons_fini(void)
|
||||
{
|
||||
/* Not much to do ? */
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<deviceinfo version="0.2">
|
||||
<device>
|
||||
|
||||
<!-- 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.
|
||||
|
||||
You MUST specify all options as strings, otherwise the server will
|
||||
ignore them.
|
||||
|
||||
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.
|
||||
|
||||
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"
|
||||
string="Linux">
|
||||
<merge key="input.x11_driver" type="string">evdev</merge>
|
||||
</match>
|
||||
<match key="/org/freedesktop/Hal/devices/computer:system.kernel.name"
|
||||
string="SunOS">
|
||||
<match key="input.device" contains="usb">
|
||||
<merge key="input.x11_options.StreamsModule" type="string">usbms</merge>
|
||||
<merge key="input.x11_options.Protocol" type="string">VUID</merge>
|
||||
</match>
|
||||
</match>
|
||||
</match>
|
||||
|
||||
<match key="info.capabilities" contains="input.keys">
|
||||
<merge key="input.x11_options.XkbRules" type="string">base</merge>
|
||||
|
||||
<!-- If we're using Linux, we use evdev by default (falling back to
|
||||
kbd otherwise). -->
|
||||
<merge key="input.x11_driver" type="string">kbd</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.x11_options.XkbModel" type="string">evdev</merge>
|
||||
</match>
|
||||
<match key="/org/freedesktop/Hal/devices/computer:system.kernel.name"
|
||||
string="SunOS">
|
||||
<match key="input.device" contains="usb">
|
||||
<merge key="input.x11_options.StreamsModule" type="string">usbkbm</merge>
|
||||
<merge key="input.x11_options.Protocol" type="string">VUID</merge>
|
||||
</match>
|
||||
</match>
|
||||
|
||||
<merge key="input.x11_options.XkbLayout" type="string">us</merge>
|
||||
|
||||
<merge key="input.x11_options.XkbVariant" type="string" />
|
||||
</match>
|
||||
</device>
|
||||
</deviceinfo>
|
|
@ -99,7 +99,6 @@ Equipment Corporation.
|
|||
#include <X11/fonts/libxfont2.h>
|
||||
#include "opaque.h"
|
||||
#include "servermd.h"
|
||||
#include "hotplug.h"
|
||||
#include "dixfont.h"
|
||||
#include "extnsionst.h"
|
||||
#include "privates.h"
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2006-2007 Daniel Stone
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Author: Daniel Stone <daniel@fooishbar.org>
|
||||
*/
|
||||
|
||||
#ifndef HOTPLUG_H
|
||||
#define HOTPLUG_H
|
||||
|
||||
#include "list.h"
|
||||
|
||||
extern _X_EXPORT void config_pre_init(void);
|
||||
extern _X_EXPORT void config_init(void);
|
||||
extern _X_EXPORT void config_fini(void);
|
||||
|
||||
/* Bump this each time you add something to the struct
|
||||
* so that drivers can easily tell what is available
|
||||
*/
|
||||
#define ODEV_ATTRIBUTES_VERSION 1
|
||||
|
||||
struct OdevAttributes {
|
||||
/* path to kernel device node - Linux e.g. /dev/dri/card0 */
|
||||
char *path;
|
||||
|
||||
/* system device path - Linux e.g. /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/drm/card1 */
|
||||
char *syspath;
|
||||
|
||||
/* DRI-style bus id */
|
||||
char *busid;
|
||||
|
||||
/* Server managed FD */
|
||||
int fd;
|
||||
|
||||
/* Major number of the device node pointed to by ODEV_ATTRIB_PATH */
|
||||
int major;
|
||||
|
||||
/* Minor number of the device node pointed to by ODEV_ATTRIB_PATH */
|
||||
int minor;
|
||||
|
||||
/* kernel driver name */
|
||||
char *driver;
|
||||
};
|
||||
|
||||
/* Note starting with xserver 1.16 this function never fails */
|
||||
struct OdevAttributes *
|
||||
config_odev_allocate_attributes(void);
|
||||
|
||||
void
|
||||
config_odev_free_attributes(struct OdevAttributes *attribs);
|
||||
|
||||
typedef void (*config_odev_probe_proc_ptr)(struct OdevAttributes *attribs);
|
||||
void config_odev_probe(config_odev_probe_proc_ptr probe_callback);
|
||||
|
||||
#ifdef CONFIG_UDEV_KMS
|
||||
void NewGPUDeviceRequest(struct OdevAttributes *attribs);
|
||||
void DeleteGPUDeviceRequest(struct OdevAttributes *attribs);
|
||||
#endif
|
||||
|
||||
#define ServerIsNotSeat0() (SeatId && strcmp(SeatId, "seat0"))
|
||||
|
||||
struct xf86_platform_device *
|
||||
xf86_find_platform_device_by_devnum(int major, int minor);
|
||||
|
||||
#endif /* HOTPLUG_H */
|
|
@ -83,16 +83,6 @@ elif cc.compiles('''
|
|||
endif
|
||||
|
||||
conf_data.set('HAVE_LIBBSD', libbsd_dep.found())
|
||||
# Note: this symbol is used by libXtrans.
|
||||
conf_data.set('HAVE_SYSTEMD_DAEMON', libsystemd_daemon_dep.found())
|
||||
conf_data.set('CONFIG_UDEV', build_udev)
|
||||
conf_data.set('CONFIG_UDEV_KMS', build_udev_kms)
|
||||
conf_data.set('HAVE_DBUS', build_dbus)
|
||||
conf_data.set('CONFIG_HAL', build_hal)
|
||||
conf_data.set('SYSTEMD_LOGIND', build_systemd_logind)
|
||||
conf_data.set('NEED_DBUS', build_systemd_logind or build_hal)
|
||||
conf_data.set('CONFIG_WSCONS', host_machine.system() == 'openbsd')
|
||||
|
||||
conf_data.set('HAVE_XSHMFENCE', xshmfence_dep.found())
|
||||
conf_data.set('WITH_LIBDRM', libdrm_required)
|
||||
conf_data.set('GLAMOR_HAS_EGL_QUERY_DMABUF',
|
||||
|
@ -273,11 +263,6 @@ endif
|
|||
conf_data.set_quoted('XKB_DFLT_RULES', get_option('xkb_default_rules'))
|
||||
conf_data.set_quoted('__XSERVERNAME__', 'Xorg')
|
||||
conf_data.set('CSRG_BASED', csrg_based)
|
||||
conf_data.set('PCCONS_SUPPORT', supports_pccons)
|
||||
conf_data.set('PCVT_SUPPORT', supports_pcvt)
|
||||
conf_data.set('SYSCONS_SUPPORT', supports_syscons)
|
||||
conf_data.set('WSCONS_SUPPORT', supports_wscons)
|
||||
conf_data.set('XSERVER_PLATFORM_BUS', build_udev_kms)
|
||||
|
||||
configure_file(output : 'dix-config.h',
|
||||
configuration : conf_data)
|
||||
|
|
52
meson.build
52
meson.build
|
@ -95,15 +95,6 @@ xkbcomp_dep = dependency('xkbcomp', required: false)
|
|||
xkbfile_dep = dependency('xkbfile')
|
||||
xfont2_dep = dependency('xfont2', version: '>= 2.0')
|
||||
|
||||
dbus_required = get_option('systemd_logind') == 'true'
|
||||
dbus_dep = dependency('dbus-1', version: '>= 1.0', required: dbus_required)
|
||||
|
||||
# libsystemd-daemon was moved into libsystemd in version 209
|
||||
libsystemd_daemon_dep = dependency('libsystemd', version: '>= 209', required: false)
|
||||
if not libsystemd_daemon_dep.found()
|
||||
libsystemd_daemon_dep = dependency('libsystemd-daemon', required: false)
|
||||
endif
|
||||
|
||||
build_hashtable = false
|
||||
|
||||
# Resolve default values of some options
|
||||
|
@ -155,23 +146,8 @@ else
|
|||
default_font_path = dfp
|
||||
endif
|
||||
|
||||
hal_option = get_option('hal')
|
||||
glamor_option = get_option('glamor')
|
||||
|
||||
build_udev = get_option('udev')
|
||||
build_udev_kms = get_option('udev_kms')
|
||||
if ['windows', 'darwin', 'cygwin'].contains(host_machine.system())
|
||||
build_udev = false
|
||||
build_udev_kms = false
|
||||
hal_option = 'false'
|
||||
endif
|
||||
|
||||
if get_option('systemd_logind') == 'auto'
|
||||
build_systemd_logind = build_udev_kms and dbus_dep.found()
|
||||
else
|
||||
build_systemd_logind = get_option('systemd_logind') == 'true'
|
||||
endif
|
||||
|
||||
with_dtrace = get_option('dtrace')
|
||||
if with_dtrace
|
||||
dtrace = find_program('dtrace', required: true)
|
||||
|
@ -215,32 +191,6 @@ else
|
|||
build_ipv6 = get_option('ipv6') == 'true'
|
||||
endif
|
||||
|
||||
hal_dep = []
|
||||
if hal_option == 'auto'
|
||||
if not build_udev
|
||||
hal_dep = dependency('hal', required: false)
|
||||
build_hal = hal_dep.found()
|
||||
else
|
||||
build_hal = false
|
||||
endif
|
||||
else
|
||||
build_hal = hal_option == 'true'
|
||||
if build_hal
|
||||
hal_dep = dependency('hal')
|
||||
endif
|
||||
endif
|
||||
|
||||
if build_udev and build_hal
|
||||
error('Hotplugging through both libudev and hal not allowed')
|
||||
endif
|
||||
|
||||
build_dbus = build_hal or build_systemd_logind
|
||||
|
||||
udev_dep = dependency('', required:false)
|
||||
if build_udev or build_udev_kms
|
||||
udev_dep = dependency('libudev', version: '>= 143')
|
||||
endif
|
||||
|
||||
if glamor_option == 'auto'
|
||||
build_glamor = build_xwayland
|
||||
else
|
||||
|
@ -437,7 +387,6 @@ common_dep = [
|
|||
xcmiscproto_dep,
|
||||
bigreqsproto_dep,
|
||||
xtrans_dep,
|
||||
libsystemd_daemon_dep,
|
||||
|
||||
videoproto_dep,
|
||||
compositeproto_dep,
|
||||
|
@ -540,7 +489,6 @@ manpage_config.set('default_font_path', default_font_path)
|
|||
subdir('include')
|
||||
|
||||
# X server core
|
||||
subdir('config')
|
||||
subdir('dix')
|
||||
subdir('dri3')
|
||||
subdir('glx')
|
||||
|
|
|
@ -43,12 +43,6 @@ option('listen_unix', type: 'boolean', value: true,
|
|||
option('listen_local', type: 'boolean', value: true,
|
||||
description: 'Listen on local by default')
|
||||
|
||||
option('udev', type: 'boolean', value: 'true')
|
||||
option('udev_kms', type: 'boolean', value: 'true')
|
||||
option('hal', type: 'combo', choices: ['true', 'false', 'auto'], value: 'auto',
|
||||
description: 'Enable HAL integration')
|
||||
option('systemd_logind', type: 'combo', choices: ['true', 'false', 'auto'], value: 'auto',
|
||||
description: 'Enable systemd-logind integration')
|
||||
option('dpms', type: 'boolean', value: true,
|
||||
description: 'Xorg DPMS extension')
|
||||
option('xf86bigfont', type: 'boolean', value: false,
|
||||
|
|
Loading…
Reference in New Issue