Duplicated device in libinput

The issue and a hack

An issue was reported that touch focus didn’t work properly in application. After a quick investigation, I found that when the issue occurs, two identical touch devices are added in weston and each touch action will trigger two same touch events (same coordinates of (X, Y) but from different struct libinput_device instances).

By a hack of ignoring the duplicate touch event in weston, touch focus works properly in application. So the next step is to find out why the touch device is being added twice and what the proper fix is.

Searching mailing list

A post in libinput mailing list mentioned duplicated device issue and also proposed a patch to prevent this issue. However, a maintainer suggested the fix should be in the place where the duplicated device comes from (udev in the case of that post):

if we get the same device twice from udev that’s a bug in udev and needs to be fixed there.

Another thread in libinput mailing list mentioned running udevadm trigger would cause device added event triggered twice:

But there is a snag: if a device like /dev/input/event0 has been coldplugged once with the hands-on technique, then all the daemons that care about it have already seen one UDev ACTION=add event for it. When the late-running ‘udevadm trigger’ does its exhaustive sweep across /sys/devices, this will cause a second ACTION=add event to be triggered for /dev/input/event0. Currently (well, with libinput 1.1.1) this causes libinput – and consequently Weston – to open a second filedescriptor against /dev/input/event0, so that all input events are received in duplicate. That confuses the compositor’s and applications’ input event handling.

That reminds me that we have a udevadm trigger in rc.weston before starting weston as a workaround of tagging the touch driver as input device type.

The proper fix

For the device adding process, libinput will first enumerate all the existing devices and add them in udev_input_add_devices(), and for hotplugged devices, libinput uses a udev monitor evdev_udev_handler() to detect ACTION=add events.

When the issue occurs, log shows the touch device is added twice in the aforementioned two parts - one in enumeration, the other in udev monitor.

And udevadm trigger in rc.weston is the cause of the second adding operation. So the fix is simply removing it as we don’t need that workaround any more.

Unmerged patch

The patch in the second thread mentioned above had been merged in this commit to fix a race between udev events and libinput startup, but the patch in the first thread wasn’t merged.

Keep a copy of that patch here for reference and in case it may help:

diff --git a/src/evdev.c b/src/evdev.c
index 99713f2c..a3cc8f48 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -2058,6 +2058,7 @@ evdev_device_create(struct libinput_seat *seat,
                    struct udev_device *udev_device)
 {
        struct libinput *libinput = seat->libinput;
+       struct libinput_device *dev = NULL;
        struct evdev_device *device = NULL;
        int rc;
        int fd;
@@ -2075,6 +2076,15 @@ evdev_device_create(struct libinput_seat *seat,
                return NULL;
        }
 
+       list_for_each(dev, &seat->devices_list, link) {
+               struct evdev_device *d = (struct evdev_device*)dev;
+               if (streq(devnode, udev_device_get_devnode(d->udev_device))) {
+                       log_info(libinput,
+                               "%s device is already opened\n", d->devname);
+                       goto err;
+               }
+       }
+
        /* Use non-blocking mode so that we can loop on read on
         * evdev_device_data() until all events on the fd are
         * read.  mtdev_get() also expects this. */

Have fun!

comments powered by Disqus