[PATCH v2 libinput 07/10] pad: implement support for the Express Key Remote

Peter Hutterer peter.hutterer at who-t.net
Wed Jun 15 06:37:40 UTC 2016


Requires the newest libwacom. For distributions that want to ship libinput but
don't have the new libwacom available: the actual minimum requirement is
libwacom 0.17 but with that test cases will fail due to wrong button labelling
for the EKR.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
Changes to v1:
- new in v2

 configure.ac                       |   2 +-
 src/evdev-tablet-pad-leds.c        | 131 ++++++++++++++++++++++++++++++++++++-
 src/evdev.c                        |   1 +
 src/evdev.h                        |   1 +
 udev/90-libinput-model-quirks.hwdb |   3 +
 5 files changed, 134 insertions(+), 4 deletions(-)

diff --git a/configure.ac b/configure.ac
index 8278be2..740deac 100644
--- a/configure.ac
+++ b/configure.ac
@@ -203,7 +203,7 @@ AC_ARG_ENABLE(libwacom,
 	      [use_libwacom="$enableval"],
 	      [use_libwacom="yes"])
 if test "x$use_libwacom" = "xyes"; then
-	PKG_CHECK_MODULES(LIBWACOM, [libwacom >= 0.17], [HAVE_LIBWACOM="yes"])
+	PKG_CHECK_MODULES(LIBWACOM, [libwacom >= 0.20], [HAVE_LIBWACOM="yes"])
 	AC_DEFINE(HAVE_LIBWACOM, 1, [Build with libwacom])
 fi
 
diff --git a/src/evdev-tablet-pad-leds.c b/src/evdev-tablet-pad-leds.c
index 87fce7a..c17e70d 100644
--- a/src/evdev-tablet-pad-leds.c
+++ b/src/evdev-tablet-pad-leds.c
@@ -23,6 +23,7 @@
 #include "config.h"
 
 #include <assert.h>
+#include <dirent.h>
 #include <limits.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -38,8 +39,10 @@
 struct pad_led_group {
 	struct libinput_tablet_pad_mode_group base;
 
-	/* /sys/devices/<hid device>/wacom_led/status_led0_select */
+	/* /sys/devices/<hid device>/wacom_led/status_led0_select or
+	  /sys/devices/<hid device>/wacom_remote/<id>/remote_mode on the EKR */
 	int led_status_fd;
+	bool self_updating;
 
 	struct list toggle_button_list;
 };
@@ -79,6 +82,15 @@ pad_led_group_set_mode(struct pad_led_group *group,
 	char buf[4] = {0};
 	int rc;
 
+	/* EKR toggles the mode automatically so we just read the new mode
+	 * from the fd */
+	if (group->self_updating) {
+		rc = pad_led_group_get_mode(group);
+		if (rc >= 0)
+			group->base.current_mode = rc;
+		return;
+	}
+
 	rc = snprintf(buf, sizeof(buf), "%d", mode);
 	if (rc == -1)
 		return;
@@ -255,6 +267,63 @@ pad_led_get_sysfs_base_path(struct evdev_device *device,
 	return rc != -1;
 }
 
+static bool
+pad_led_get_sysfs_ekr_path(struct evdev_device *device,
+			   char *path_out,
+			   size_t path_out_sz)
+{
+	const char *hid_sysfs_path;
+	char path[PATH_MAX];
+	int rc;
+	DIR *dirp;
+	struct dirent *dp;
+	int serial = 0;
+
+	hid_sysfs_path = pad_get_hid_sysfs_base_path(device);
+	if (hid_sysfs_path == NULL)
+		return false;
+
+	rc = snprintf(path, sizeof(path), "%s/wacom_remote", hid_sysfs_path);
+	if (rc == -1)
+		return false;
+
+	dirp = opendir(path);
+	if (!dirp)
+		return false;
+
+	while ((dp = readdir(dirp)) != NULL) {
+		if (dp->d_name[0] == '.')
+			continue;
+
+		/* There should be one entry per remote: the remote's serial
+		 * in decimal notation. We always return
+		 * the first we find, multiple remotes is not supported yet.
+		 */
+		if (safe_atoi(dp->d_name, &serial))
+			break;
+	}
+	closedir(dirp);
+
+	if (serial == 0)
+		return false;
+
+	rc = snprintf(path_out,
+		      path_out_sz,
+		      "%s/wacom_remote/%d/remote_mode",
+		      hid_sysfs_path,
+		      serial);
+	if (rc == -1)
+		return false;
+
+	rc = access(path, R_OK);
+	if (rc == -1)
+		log_error(device->base.seat->libinput,
+			  "Unable to access EKR LED syspath %s (%s)\n",
+			  path_out,
+			  strerror(errno));
+	return rc != -1;
+}
+
 #if HAVE_LIBWACOM
 static int
 pad_init_led_groups(struct pad_dispatch *pad,
@@ -316,6 +385,51 @@ pad_init_led_groups(struct pad_dispatch *pad,
 
 	return 0;
 }
+
+static int
+pad_init_ekr_group(struct pad_dispatch *pad,
+		   struct evdev_device *device,
+		   WacomDevice *wacom)
+{
+	struct libinput *libinput = device->base.seat->libinput;
+	struct pad_led_group *group;
+	char syspath[PATH_MAX];
+	int rc = 1;
+	int fd;
+
+	if (!pad_led_get_sysfs_ekr_path(device, syspath, sizeof(syspath)))
+		return 1;
+
+	/* EKR has 3 LEDs, hardwired to the toggle button */
+	group = pad_group_new_basic(pad, 0, 3);
+	if (!group)
+		return 1;
+
+	fd = open_restricted(libinput, syspath, O_RDONLY);
+	if (fd < 0) {
+		errno = -fd;
+		goto error;
+	}
+	group->led_status_fd = fd;
+	group->self_updating = true;
+
+	rc = pad_led_group_get_mode(group);
+	if (rc < 0) {
+		errno = -rc;
+		goto error;
+	}
+
+	group->base.current_mode = rc;
+
+	list_insert(&pad->modes.mode_group_list, &group->base.link);
+
+	return 0;
+error:
+	log_error(libinput, "Unable to init EKR LED group: %s\n", strerror(errno));
+
+	free(group);
+	return 1;
+}
 #endif
 
 static inline struct libinput_tablet_pad_mode_group *
@@ -401,6 +515,13 @@ pad_init_mode_rings(struct pad_dispatch *pad, WacomDevice *wacom)
 	const WacomStatusLEDs *leds;
 	int i, nleds;
 
+	/* the LED of the EKR is hardwired so libwacom doesn't export it */
+	if (pad->device->model_flags & EVDEV_MODEL_WACOM_EKR) {
+		group = pad_get_mode_group(pad, 0);
+		group->ring_mask |= 0x1;
+		return;
+	}
+
 	leds = libwacom_get_status_leds(wacom, &nleds);
 	if (nleds == 0)
 		return;
@@ -471,7 +592,12 @@ pad_init_leds_from_libwacom(struct pad_dispatch *pad,
 	if (!wacom)
 		goto out;
 
-	if (pad_init_led_groups(pad, device, wacom) != 0)
+	if (libwacom_get_class(wacom) == WCLASS_REMOTE)
+		rc = pad_init_ekr_group(pad, device, wacom);
+	else
+		rc = pad_init_led_groups(pad, device, wacom);
+
+	if (rc != 0)
 		goto out;
 
 	if ((rc = pad_init_mode_buttons(pad, wacom)) != 0)
@@ -480,7 +606,6 @@ pad_init_leds_from_libwacom(struct pad_dispatch *pad,
 	pad_init_mode_rings(pad, wacom);
 	pad_init_mode_strips(pad, wacom);
 
-	rc = 0;
 out:
 	if (wacom)
 		libwacom_destroy(wacom);
diff --git a/src/evdev.c b/src/evdev.c
index e18492a..0cd9365 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -1806,6 +1806,7 @@ evdev_read_model_flags(struct evdev_device *device)
 		MODEL(LENOVO_T450_TOUCHPAD),
 		MODEL(PRECISE_TOUCHPAD),
 		MODEL(TRACKBALL),
+		MODEL(WACOM_EKR),
 		{ NULL, EVDEV_MODEL_DEFAULT },
 #undef MODEL
 	};
diff --git a/src/evdev.h b/src/evdev.h
index 9d6108c..caaf75c 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -116,6 +116,7 @@ enum evdev_device_model {
 	EVDEV_MODEL_LENOVO_T450_TOUCHPAD= (1 << 17),
 	EVDEV_MODEL_PRECISE_TOUCHPAD = (1 << 18),
 	EVDEV_MODEL_TRACKBALL = (1 << 19),
+	EVDEV_MODEL_WACOM_EKR = (1 << 20),
 };
 
 struct mt_slot {
diff --git a/udev/90-libinput-model-quirks.hwdb b/udev/90-libinput-model-quirks.hwdb
index 821bc16..ee628b4 100644
--- a/udev/90-libinput-model-quirks.hwdb
+++ b/udev/90-libinput-model-quirks.hwdb
@@ -143,6 +143,9 @@ libinput:name:SynPS/2 Synaptics TouchPad:dmi:*svnSystem76*pvrkudp1*
 libinput:touchpad:input:b0003v056Ap*
  LIBINPUT_MODEL_WACOM_TOUCHPAD=1
 
+libinput:name:*Wacom Express Key Remote Pad:dmi:*
+ LIBINPUT_MODEL_WACOM_EKR=1
+
 ##########################################
 # Anything that has trackball in the name
 ##########################################
-- 
2.7.4



More information about the wayland-devel mailing list