Compare commits

...

10 Commits

Author SHA1 Message Date
Peter Hutterer
76b1d58a97 evdev 2.7.0
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2012-03-07 20:39:09 +10:00
Peter Hutterer
224a28de25 Only force REL_X/Y if no ABS_X/Y exists
5c5b2c8db8 added forced x/y axes if a device
has any axes of the same mode. This was too broad a brush, some devices have
a relative wheel but absolute x/y axes and would now get misdetected as
purely relative device.

Only force relative axes if a device no rel x/y _and_ no abs x/y.

Reproducible: virtual machine with QEMU USB Tablet will stop working

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Chase Douglas <chase.douglas@canonical.com>
2012-01-26 16:07:10 +10:00
Chase Douglas
bc2f01ab83 Copy last valuator values into new touch valuator masks
Evdev is a 100% stateful protocol. The following represents three
touches. Two touches begin and end at the same time at (500, 500) and
(1000, 1000). The third touch begins after the first two end, and is at
(500, 500).

ABS_MT_SLOT		0	/* Set touch slot */
ABS_MT_TRACKING_ID	0	/* New touch with ID 0 in slot 0 */
ABS_MT_POSITION_X	500	/* Initial X position */
ABS_MT_POSITION_Y	500	/* Initial Y position */
ABS_MT_SLOT		1	/* Set touch slot */
ABS_MT_TRACKING_ID	1	/* New touch with ID 1 in slot 1 */
ABS_MT_POSITION_X	1000	/* Initial X position */
ABS_MT_POSITION_Y	1000	/* Initial Y position */
SYNC				/* End of frame */
ABS_MT_SLOT		0	/* Go back to slot 0 */
ABS_MT_TRACKING_ID	-1	/* Touch in slot 0 ended */
ABS_MT_SLOT		1	/* Go to slot 1 */
ABS_MT_TRACKING_ID	-1	/* Touch in slot 1 ended */
SYNC				/* End of frame */
ABS_MT_SLOT		0	/* Go back to slot 0 */
ABS_MT_TRACKING_ID	2	/* New touch in slot 0 with ID 2 */
SYNC				/* End of frame */
ABS_MT_TRACKING_ID	-1	/* Touch in last slot (0) ended */
SYNC				/* End of frame */

Note that touch 2 has the same X and Y position as touch 0. This is
implied because no new value was emitted for slot 0. In fact, Linux will
not emit an event in the same slot with the same event type and code
unless the value has changed. Thus, we can only assume that all the MT
valuators have the same values as they were when they were last sent for
the given slot.

This change adds an array of valuator mask to hold all the last valuator
values that came from evdev for each slot. When a new touch begins, all
the last values are copied into it.

This patch assumes initial axis values of 0 in each slot. Linux and
mtdev do not provide a facility to query the current values of axes in
each slot yet. This may cause spurious incorrect touch valuator values
at the beginning of an X session, but there's nothing we can do about it
right now.

Signed-off-by: Chase Douglas <chase.douglas@canonical.com>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2012-01-24 12:12:47 +10:00
Peter Hutterer
9d9c9870c8 Prefere relative axis labelling over absolute axis labelling
If a device has both relative and absolute axes, we'd initialise the
relative axes but label them with the absolute labels.

The current code is broken for mixed mode devices. Most of these devices
operate primarily in relative mode, but have some absolute axes available
for secondary functionality. For now, label the relative axes properly. We
can fix the absolute axes later.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Chase Douglas <chase.douglas@canonical.com>
2012-01-18 16:47:16 +10:00
Peter Hutterer
5c5b2c8db8 Force x/y axes to exist on devices with any other axes (#44655)
Too much in the server relies on x/y to exist and to be axes 0 and 1. So if
any relative axes exist, initialize REL_X/Y or ABS_X/Y as well.

For servers up to 1.11: a scrollwheel-only device now has relative axes
where it only had buttons before.

For servers 1.12 or later: the device now has x/y in addition to the scroll
axes.

X.Org Bug 44655 <http://bugs.freedesktop.org/show_bug.cgi?id=44655>

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Chase Douglas <chase.douglas@canonical.com>
Reviewed-by: Daniel Stone <daniel@fooishbar.org>
2012-01-17 14:33:54 +10:00
Pete Beardmore
854df75f49 missing multitouch related define tests
addition of two missing define tests required when no multitouch related
symbols are available in user-space

Fixes X.Org Bug 44578 <https://bugs.freedesktop.org/show_bug.cgi?id=44578>

Signed-off-by: Pete Beardmore <pete.beardmore@msn.com>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2012-01-10 10:56:45 +10:00
Chase Douglas
8c55e94a6a Set the default resolution to 0
If we don't know the resolution, set it to 0. This is invalid, and tells
the X client that we don't know the resolution, rather than reporting an
incorrect value.

This value was originally from commit
6271494faa, which is the initial commit
from Adam Jackson adding absolute axis support.

Signed-off-by: Chase Douglas <chase.douglas@canonical.com>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2012-01-06 12:17:00 +10:00
Peter Hutterer
965338e9d0 Remove unused udev.c
Added in 683a55e504 due to a botched up
rebase -i. The contents of udev.c and EvdevIsVirtual are identical, there is
no need for an extra file for this one function.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2012-01-03 08:44:27 +10:00
Cyril Brulebois
0075da20d6 configure.ac: Fix udev/libudev dependency.
In 683a55e504, a dependency on libudev was
added, but documented in configure.ac as a dependency on udev (which
also happens to ship a pkg-config file).

Signed-off-by: Cyril Brulebois <kibi@debian.org>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2012-01-03 08:40:02 +10:00
Jeremy Huddleston
009ac94a8e Remove redundant redeclaration of Evdev3BEmuPreInit
Found-by: Tinderbox
Signed-off-by: Jeremy Huddleston <jeremyhu@apple.com>
2011-12-31 21:28:53 -05:00
4 changed files with 159 additions and 108 deletions

View File

@@ -23,7 +23,7 @@
# Initialize Autoconf
AC_PREREQ([2.60])
AC_INIT([xf86-input-evdev],
[2.6.99.901],
[2.7.0],
[https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
[xf86-input-evdev])
AC_CONFIG_SRCDIR([Makefile.am])
@@ -46,7 +46,7 @@ XORG_DEFAULT_OPTIONS
# Obtain compiler/linker options from server and required extensions
PKG_CHECK_MODULES(XORG, [xorg-server >= 1.10] xproto inputproto)
PKG_CHECK_MODULES(UDEV, udev)
PKG_CHECK_MODULES(UDEV, libudev)
PKG_CHECK_MODULES(XI22, [inputproto >= 2.1.99.3] [xorg-server >= 1.11.99.901], HAVE_XI22="yes", HAVE_XI22="no")

View File

@@ -120,7 +120,7 @@ static BOOL EvdevGrabDevice(InputInfoPtr pInfo, int grab, int ungrab);
static void EvdevSetCalibration(InputInfoPtr pInfo, int num_calibration, int calibration[4]);
static int EvdevOpenDevice(InputInfoPtr pInfo);
static void EvdevInitAxesLabels(EvdevPtr pEvdev, int natoms, Atom *atoms);
static void EvdevInitAxesLabels(EvdevPtr pEvdev, int mode, int natoms, Atom *atoms);
static void EvdevInitButtonLabels(EvdevPtr pEvdev, int natoms, Atom *atoms);
static void EvdevInitProperty(DeviceIntPtr dev);
static int EvdevSetProperty(DeviceIntPtr dev, Atom atom,
@@ -746,6 +746,24 @@ EvdevProcessTouch(InputInfoPtr pInfo)
valuator_mask_zero(pEvdev->mt_mask);
}
static int
num_slots(EvdevPtr pEvdev)
{
int value = pEvdev->absinfo[ABS_MT_SLOT].maximum -
pEvdev->absinfo[ABS_MT_SLOT].minimum + 1;
/* If we don't know how many slots there are, assume at least 10 */
return value > 1 ? value : 10;
}
static int
last_mt_vals_slot(EvdevPtr pEvdev)
{
int value = pEvdev->cur_slot - pEvdev->absinfo[ABS_MT_SLOT].minimum;
return value < num_slots(pEvdev) ? value : -1;
}
static void
EvdevProcessTouchEvent(InputInfoPtr pInfo, struct input_event *ev)
{
@@ -757,16 +775,29 @@ EvdevProcessTouchEvent(InputInfoPtr pInfo, struct input_event *ev)
pEvdev->cur_slot = ev->value;
} else
{
int slot_index = last_mt_vals_slot(pEvdev);
if (pEvdev->slot_state == SLOTSTATE_EMPTY)
pEvdev->slot_state = SLOTSTATE_UPDATE;
if (ev->code == ABS_MT_TRACKING_ID) {
if (ev->value >= 0)
pEvdev->slot_state = SLOTSTATE_OPEN;
else
pEvdev->slot_state = SLOTSTATE_CLOSE;
if (ev->value >= 0) {
pEvdev->slot_state = SLOTSTATE_OPEN;
if (slot_index >= 0)
valuator_mask_copy(pEvdev->mt_mask,
pEvdev->last_mt_vals[slot_index]);
else
xf86IDrvMsg(pInfo, X_WARNING,
"Attempted to copy values from out-of-range "
"slot, touch events may be incorrect.\n");
} else
pEvdev->slot_state = SLOTSTATE_CLOSE;
} else {
map = pEvdev->axis_map[ev->code];
valuator_mask_set(pEvdev->mt_mask, map, ev->value);
if (slot_index >= 0)
valuator_mask_set(pEvdev->last_mt_vals[slot_index], map,
ev->value);
}
}
}
@@ -1027,6 +1058,28 @@ EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev)
#undef ABS_Y_VALUE
#undef ABS_VALUE
static void
EvdevFreeMasks(EvdevPtr pEvdev)
{
int i;
valuator_mask_free(&pEvdev->vals);
valuator_mask_free(&pEvdev->old_vals);
valuator_mask_free(&pEvdev->prox);
#ifdef MULTITOUCH
valuator_mask_free(&pEvdev->mt_mask);
if (pEvdev->last_mt_vals)
{
for (i = 0; i < num_slots(pEvdev); i++)
valuator_mask_free(&pEvdev->last_mt_vals[i]);
free(pEvdev->last_mt_vals);
pEvdev->last_mt_vals = NULL;
}
for (i = 0; i < EVDEV_MAXQUEUE; i++)
valuator_mask_free(&pEvdev->queue[i].touchMask);
#endif
}
/* just a magic number to reduce the number of reads */
#define NUM_EVENTS 16
@@ -1143,6 +1196,7 @@ EvdevAddKeyClass(DeviceIntPtr device)
return Success;
}
#ifdef MULTITOUCH
/* MT axes are counted twice - once as ABS_X (which the kernel keeps for
* backwards compatibility), once as ABS_MT_POSITION_X. So we need to keep a
* mapping of those axes to make sure we only count them once
@@ -1160,6 +1214,7 @@ static struct mt_axis_mappings mt_axis_mappings[] = {
{ABS_MT_PRESSURE, ABS_PRESSURE},
{ABS_MT_DISTANCE, ABS_DISTANCE},
};
#endif
/**
* return TRUE if the axis is not one we should count as true axis
@@ -1256,6 +1311,24 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device)
goto out;
}
pEvdev->last_mt_vals = calloc(num_slots(pEvdev), sizeof(ValuatorMask *));
if (!pEvdev->last_mt_vals) {
xf86IDrvMsg(pInfo, X_ERROR,
"%s: failed to allocate MT last values mask array.\n",
device->name);
goto out;
}
for (i = 0; i < num_slots(pEvdev); i++) {
pEvdev->last_mt_vals[i] = valuator_mask_new(num_mt_axes_total);
if (!pEvdev->last_mt_vals[i]) {
xf86IDrvMsg(pInfo, X_ERROR,
"%s: failed to allocate MT last values mask.\n",
device->name);
goto out;
}
}
for (i = 0; i < EVDEV_MAXQUEUE; i++) {
pEvdev->queue[i].touchMask =
valuator_mask_new(num_mt_axes_total);
@@ -1280,6 +1353,7 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device)
mapping = i;
#ifdef MULTITOUCH
for (j = 0; j < ArrayLength(mt_axis_mappings); j++)
{
if (mt_axis_mappings[j].code == axis)
@@ -1288,13 +1362,13 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device)
mt_axis_mappings[j].needs_mapping)
mapping = mt_axis_mappings[j].mapping;
}
#endif
pEvdev->axis_map[axis] = mapping;
if (mapping == i)
i++;
}
EvdevInitAxesLabels(pEvdev, pEvdev->num_vals + num_mt_axes, atoms);
EvdevInitAxesLabels(pEvdev, Absolute, pEvdev->num_vals + num_mt_axes, atoms);
if (!InitValuatorClassDeviceStruct(device, num_axes + num_mt_axes, atoms,
GetMotionHistorySize(), Absolute)) {
@@ -1318,12 +1392,23 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device)
device->name);
goto out;
}
for (i = 0; i < num_slots(pEvdev); i++) {
for (axis = ABS_MT_TOUCH_MAJOR; axis < ABS_MAX; axis++) {
if (pEvdev->axis_map[axis] >= 0) {
/* XXX: read initial values from mtdev when it adds support
* for doing so. */
valuator_mask_set(pEvdev->last_mt_vals[i],
pEvdev->axis_map[axis], 0);
}
}
}
}
#endif
for (axis = ABS_X; axis < ABS_MT_SLOT; axis++) {
int axnum = pEvdev->axis_map[axis];
int resolution = 10000;
int resolution = 0;
if (axnum == -1)
continue;
@@ -1345,7 +1430,7 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device)
#ifdef MULTITOUCH
for (axis = ABS_MT_TOUCH_MAJOR; axis <= ABS_MAX; axis++) {
int axnum = pEvdev->axis_map[axis];
int resolution = 10000;
int resolution = 0;
int j;
BOOL skip = FALSE;
@@ -1423,14 +1508,7 @@ EvdevAddAbsValuatorClass(DeviceIntPtr device)
return Success;
out:
valuator_mask_free(&pEvdev->vals);
valuator_mask_free(&pEvdev->old_vals);
valuator_mask_free(&pEvdev->prox);
#ifdef MULTITOUCH
valuator_mask_free(&pEvdev->mt_mask);
for (i = 0; i < EVDEV_MAXQUEUE; i++)
valuator_mask_free(&pEvdev->queue[i].touchMask);
#endif
EvdevFreeMasks(pEvdev);
return !Success;
}
@@ -1493,7 +1571,7 @@ EvdevAddRelValuatorClass(DeviceIntPtr device)
i++;
}
EvdevInitAxesLabels(pEvdev, pEvdev->num_vals, atoms);
EvdevInitAxesLabels(pEvdev, Relative, pEvdev->num_vals, atoms);
if (!InitValuatorClassDeviceStruct(device, num_axes, atoms,
GetMotionHistorySize(), Relative)) {
@@ -1764,9 +1842,6 @@ EvdevProc(DeviceIntPtr device, int what)
{
InputInfoPtr pInfo;
EvdevPtr pEvdev;
#ifdef MULTITOUCH
int i;
#endif
pInfo = device->public.devicePrivate;
pEvdev = pInfo->private;
@@ -1803,16 +1878,7 @@ EvdevProc(DeviceIntPtr device, int what)
close(pInfo->fd);
pInfo->fd = -1;
}
valuator_mask_free(&pEvdev->vals);
valuator_mask_free(&pEvdev->old_vals);
valuator_mask_free(&pEvdev->prox);
#ifdef MULTITOUCH
valuator_mask_free(&pEvdev->mt_mask);
for (i = 0; i < EVDEV_MAXQUEUE; i++)
valuator_mask_free(&pEvdev->queue[i].touchMask);
if (pEvdev->mtdev)
mtdev_close(pEvdev->mtdev);
#endif
EvdevFreeMasks(pEvdev);
EvdevRemoveDevice(pInfo);
pEvdev->min_maj = 0;
break;
@@ -1955,6 +2021,38 @@ EvdevGrabDevice(InputInfoPtr pInfo, int grab, int ungrab)
return TRUE;
}
/**
* Some devices only have other axes (e.g. wheels), but we
* still need x/y for these. The server relies on devices having
* x/y as axes 0/1 and core/XI 1.x clients expect it too (#44655)
*/
static void
EvdevForceXY(InputInfoPtr pInfo, int mode)
{
EvdevPtr pEvdev = pInfo->private;
xf86IDrvMsg(pInfo, X_INFO, "Forcing %s x/y axes to exist.\n",
(mode == Relative) ? "relative" : "absolute");
if (mode == Relative)
{
EvdevSetBit(pEvdev->rel_bitmask, REL_X);
EvdevSetBit(pEvdev->rel_bitmask, REL_Y);
} else if (mode == Absolute)
{
EvdevSetBit(pEvdev->abs_bitmask, ABS_X);
EvdevSetBit(pEvdev->abs_bitmask, ABS_Y);
pEvdev->absinfo[ABS_X].minimum = 0;
pEvdev->absinfo[ABS_X].maximum = 1000;
pEvdev->absinfo[ABS_X].value = 0;
pEvdev->absinfo[ABS_X].resolution = 0;
pEvdev->absinfo[ABS_Y].minimum = 0;
pEvdev->absinfo[ABS_Y].maximum = 1000;
pEvdev->absinfo[ABS_Y].value = 0;
pEvdev->absinfo[ABS_Y].resolution = 0;
}
}
static int
EvdevProbe(InputInfoPtr pInfo)
{
@@ -2048,7 +2146,9 @@ EvdevProbe(InputInfoPtr pInfo)
if (EvdevBitIsSet(pEvdev->rel_bitmask, REL_X) &&
EvdevBitIsSet(pEvdev->rel_bitmask, REL_Y)) {
xf86IDrvMsg(pInfo, X_PROBED, "Found x and y relative axes\n");
}
} else if (!EvdevBitIsSet(pEvdev->abs_bitmask, ABS_X) ||
!EvdevBitIsSet(pEvdev->abs_bitmask, ABS_Y))
EvdevForceXY(pInfo, Relative);
} else {
xf86IDrvMsg(pInfo, X_INFO, "Relative axes present but ignored.\n");
has_rel_axes = FALSE;
@@ -2113,7 +2213,16 @@ EvdevProbe(InputInfoPtr pInfo)
pEvdev->flags |= EVDEV_TOUCHSCREEN;
pEvdev->flags |= EVDEV_BUTTON_EVENTS;
}
} else {
#ifdef MULTITOUCH
if (!EvdevBitIsSet(pEvdev->abs_bitmask, ABS_MT_POSITION_X) ||
!EvdevBitIsSet(pEvdev->abs_bitmask, ABS_MT_POSITION_Y))
#endif
EvdevForceXY(pInfo, Absolute);
}
}
for (i = 0; i < BTN_MISC; i++) {
@@ -2592,18 +2701,18 @@ static char* btn_labels[][16] = {
}
};
static void EvdevInitAxesLabels(EvdevPtr pEvdev, int natoms, Atom *atoms)
static void EvdevInitAxesLabels(EvdevPtr pEvdev, int mode, int natoms, Atom *atoms)
{
Atom atom;
int axis;
char **labels;
int labels_len = 0;
if (pEvdev->flags & EVDEV_ABSOLUTE_EVENTS)
if (mode == Absolute)
{
labels = abs_labels;
labels_len = ArrayLength(abs_labels);
} else if ((pEvdev->flags & EVDEV_RELATIVE_EVENTS))
} else if (mode == Relative)
{
labels = rel_labels;
labels_len = ArrayLength(rel_labels);
@@ -2765,8 +2874,19 @@ EvdevInitProperty(DeviceIntPtr dev)
/* Axis labelling */
if ((pEvdev->num_vals > 0) && (prop_axis_label = XIGetKnownProperty(AXIS_LABEL_PROP)))
{
int mode;
Atom atoms[pEvdev->num_vals];
EvdevInitAxesLabels(pEvdev, pEvdev->num_vals, atoms);
if (pEvdev->flags & EVDEV_ABSOLUTE_EVENTS)
mode = Absolute;
else if (pEvdev->flags & EVDEV_RELATIVE_EVENTS)
mode = Relative;
else {
xf86IDrvMsg(pInfo, X_ERROR, "BUG: mode is neither absolute nor relative\n");
mode = Absolute;
}
EvdevInitAxesLabels(pEvdev, mode, pEvdev->num_vals, atoms);
XIChangeDeviceProperty(dev, prop_axis_label, XA_ATOM, 32,
PropModeReplace, pEvdev->num_vals, atoms, FALSE);
XISetDevicePropertyDeletable(dev, prop_axis_label, FALSE);

View File

@@ -158,6 +158,7 @@ typedef struct {
ValuatorMask *old_vals; /* old values for calculating relative motion */
ValuatorMask *prox; /* last values set while not in proximity */
ValuatorMask *mt_mask;
ValuatorMask **last_mt_vals;
int cur_slot;
enum SlotState slot_state;
#ifdef MULTITOUCH
@@ -278,7 +279,6 @@ void EvdevMBEmuFinalize(InputInfoPtr);
CARD32 Evdev3BEmuTimer(OsTimerPtr timer, CARD32 time, pointer arg);
BOOL Evdev3BEmuFilterEvent(InputInfoPtr, int, BOOL);
void Evdev3BEmuPreInit(InputInfoPtr pInfo);
void Evdev3BEmuPreInit(InputInfoPtr);
void Evdev3BEmuOn(InputInfoPtr);
void Evdev3BEmuFinalize(InputInfoPtr);
void Evdev3BEmuProcessRelMotion(InputInfoPtr pInfo, int dx, int dy);

View File

@@ -1,69 +0,0 @@
/*
* Copyright © 2011 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of Red Hat
* not be used in advertising or publicity pertaining to distribution
* of the software without specific, written prior permission. Red
* Hat makes no representations about the suitability of this software
* for any purpose. It is provided "as is" without express or implied
* warranty.
*
* THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Authors:
* Peter Hutterer (peter.hutterer@redhat.com)
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "evdev.h"
#include <libudev.h>
#include <sys/types.h>
#include <sys/stat.h>
Bool
udev_device_is_virtual(const char* devicenode)
{
struct udev *udev = NULL;
struct udev_device *device = NULL;
struct stat st;
int rc = FALSE;
const char *devpath;
udev = udev_new();
if (!udev)
goto out;
stat(devicenode, &st);
device = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
if (!device)
goto out;
devpath = udev_device_get_devpath(device);
if (!devpath)
goto out;
if (strstr(devpath, "LNXSYSTM"))
rc = TRUE;
out:
udev_device_unref(device);
udev_unref(udev);
return rc;
}