[PATCH libevdev] uinput: Add ioctl to get the sysname of the created input device

Benjamin Tissoires benjamin.tissoires at gmail.com
Fri Jan 17 11:08:00 PST 2014


From: Benjamin Tisssoires <benjamin.tissoires at gmail.com>

The kernel shipping uinput version >= 4 can give us the sysname of the created
input device. This allows to retrieve for sure the name of the input node in /dev/input/,
whereas the current implementation relies on a heuristic which may fail if two
uinput device are created at the same time.

If the kernel supports the ioctl, it will return a different code than -EINVAL, so
if it does not support this new ioctl, rely on our old heuristic.

Signed-off-by: Benjamin Tisssoires <benjamin.tissoires at gmail.com>
---

Hi guys,

I am posting this patch here while I am submitting the kernel part. So, as long
as the kernel part is not taken, this one stays as an RFC and consider this for
history records.

Of course, reviews are still welcome :)

Cheers,
Benjamin

 libevdev/libevdev-uinput-int.h |  3 +++
 libevdev/libevdev-uinput.c     | 46 ++++++++++++++++++++++++++++++++++++++----
 2 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/libevdev/libevdev-uinput-int.h b/libevdev/libevdev-uinput-int.h
index fbc1c29..ab50fa1 100644
--- a/libevdev/libevdev-uinput-int.h
+++ b/libevdev/libevdev-uinput-int.h
@@ -20,6 +20,9 @@
  * OF THIS SOFTWARE.
  */
 
+#ifndef UI_GET_SYSNAME
+#define UI_GET_SYSNAME(len)	_IOC(_IOC_READ, UINPUT_IOCTL_BASE, 300, len)
+#endif
 
 struct libevdev_uinput {
 	int fd; /**< file descriptor to uinput */
diff --git a/libevdev/libevdev-uinput.c b/libevdev/libevdev-uinput.c
index ea9cf78..409fcce 100644
--- a/libevdev/libevdev-uinput.c
+++ b/libevdev/libevdev-uinput.c
@@ -203,13 +203,34 @@ static int is_input_device(const struct dirent *dent) {
 }
 
 static int
-fetch_syspath_and_devnode(struct libevdev_uinput *uinput_dev)
+fetch_syspath_from_ioctl(struct libevdev_uinput *uinput_dev)
+{
+	int ret;
+	char name[64];
+	char path[sizeof(SYS_INPUT_DIR) + sizeof(name)] = SYS_INPUT_DIR;
+
+	ret = ioctl(uinput_dev->fd, UI_GET_SYSNAME(sizeof(name)), name);
+	if (ret < 0)
+		return ret;
+
+	if (ret == sizeof(name)) {
+		log_bug("error: incomplete sysfs name: \"%s\" (len %d)\n", name, ret - 1);
+		return -ENAMETOOLONG;
+	}
+
+	strcat(path, name);
+
+	uinput_dev->syspath = strdup(path);
+
+	return 0;
+}
+
+static int
+fetch_syspath_from_heuristic(struct libevdev_uinput *uinput_dev)
 {
 	struct dirent **namelist;
 	int ndev, i;
 
-	/* FIXME: use new ioctl() here once kernel supports it */
-
 	ndev = scandir(SYS_INPUT_DIR, &namelist, is_input_device, alphasort);
 	if (ndev <= 0)
 		return -1;
@@ -251,7 +272,6 @@ fetch_syspath_and_devnode(struct libevdev_uinput *uinput_dev)
 				strcpy(buf, SYS_INPUT_DIR);
 				strcat(buf, namelist[i]->d_name);
 				uinput_dev->syspath = strdup(buf);
-				uinput_dev->devnode = fetch_device_node(buf);
 			}
 		}
 	}
@@ -260,6 +280,24 @@ fetch_syspath_and_devnode(struct libevdev_uinput *uinput_dev)
 		free(namelist[i]);
 	free(namelist);
 
+	return uinput_dev->syspath ? 0 : -1;
+}
+
+static int
+fetch_syspath_and_devnode(struct libevdev_uinput *uinput_dev)
+{
+	int ret;
+
+	ret = fetch_syspath_from_ioctl(uinput_dev);
+	if (ret == -EINVAL)
+		/* ioctl not available with the current kernel, try the old method */
+		ret = fetch_syspath_from_heuristic(uinput_dev);
+
+	if (ret)
+		return -1;
+
+	uinput_dev->devnode = fetch_device_node(uinput_dev->syspath);
+
 	return uinput_dev->devnode ? 0 : -1;
 }
 
-- 
1.8.3.1



More information about the Input-tools mailing list