[PATCH libinput 5/9] udev: add Elantech touchpad firmware detection

Hans de Goede hdegoede at redhat.com
Wed Jul 8 05:34:43 PDT 2015


Hi,

On 01-07-15 08:08, Peter Hutterer wrote:
> Only firmware v4 (and probably whatever comes in the future) have resolution
> set, for the first couple of touchpads we need size hints. Add a callout that
> looks at the properties on the touchpad and decides the firmware version.
>
> The udev/hwdb is two-stage: the callout sets LIBINPUT_MODEL_FIRMWARE_VERSION
> which is then used in the hwdb to look up the actual size hint. This way we
> can keep the code relatively stable, the actual database of entries is just a
> text file.
>
> Size for the touchpads is pretty much arbitrary at this point. The v1, v2
> sizes are the ones from a Lenovo T61 which is a Synaptics touchpad but
> probably the same vintage.
>
> Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
> ---
>   udev/.gitignore                        |   1 +
>   udev/90-libinput-model-quirks.hwdb     |  12 ++-
>   udev/90-libinput-model-quirks.rules.in |  15 +++-
>   udev/Makefile.am                       |  10 ++-
>   udev/libinput-model-quirks.c           | 146 +++++++++++++++++++++++++++++++++
>   5 files changed, 181 insertions(+), 3 deletions(-)
>   create mode 100644 udev/libinput-model-quirks.c
>
> diff --git a/udev/.gitignore b/udev/.gitignore
> index 72c77a0..2fdaedc 100644
> --- a/udev/.gitignore
> +++ b/udev/.gitignore
> @@ -1,2 +1,3 @@
>   libinput-device-group
> +libinput-model-quirks
>   *.rules
> diff --git a/udev/90-libinput-model-quirks.hwdb b/udev/90-libinput-model-quirks.hwdb
> index cf57e9c..3bfffbb 100644
> --- a/udev/90-libinput-model-quirks.hwdb
> +++ b/udev/90-libinput-model-quirks.hwdb
> @@ -11,7 +11,7 @@
>   # Match string formats:
>   #	libinput:<modalias>
>   #	libinput:name:<name>:dmi:<dmi string>
> -
> +#	libinput:name:<name>:fwversion:<version>
>   #
>   # Sort by brand, model
>
> @@ -30,6 +30,16 @@ libinput:touchpad:input:b0005v05ACp*
>    LIBINPUT_MODEL_APPLE_TOUCHPAD=1
>
>   ##########################################
> +# Elantech
> +##########################################
> +libinput:name:*Elantech*:fwversion:1
> +libinput:name:*Elantech*:fwversion:2
> + LIBINPUT_ATTR_SIZE_HINT=55x38
> +
> +libinput:name:*Elantech*:fwversion:3
> + LIBINPUT_ATTR_SIZE_HINT=70x50
> +
> +##########################################
>   # Google
>   ##########################################
>
> diff --git a/udev/90-libinput-model-quirks.rules.in b/udev/90-libinput-model-quirks.rules.in
> index 43674f5..fec071a 100644
> --- a/udev/90-libinput-model-quirks.rules.in
> +++ b/udev/90-libinput-model-quirks.rules.in
> @@ -11,6 +11,20 @@
>   ACTION!="add|change", GOTO="libinput_model_quirks_end"
>   KERNEL!="event*", GOTO="libinput_model_quirks_end"
>
> +# Touchpad firmware detection, two-stage process.
> +# First, run the program and import the LIBINPUT_MODEL_FIRMWARE_VERSION
> +# environment (if any)
> +KERNELS=="*input*", \
> +  ENV{ID_INPUT_TOUCHPAD}=="1", \
> +  IMPORT{program}="@UDEV_TEST_PATH at libinput-model-quirks %S%p"
> +
> +# Second, match on anything with that env set and import from the hwdb
> +KERNELS=="*input*", \
> +  ENV{ID_INPUT_TOUCHPAD}=="1", \
> +  ENV{LIBINPUT_MODEL_FIRMWARE_VERSION}!="", \
> +  IMPORT{builtin}="hwdb 'libinput:name:$attr{name}:fwversion:$env{LIBINPUT_MODEL_FIRMWARE_VERSION}'"
> +# End of touchpad firmware detection
> +
>   # Matches below are exclusive, if one matches we skip the rest
>   # hwdb matches:
>   #
> @@ -24,5 +38,4 @@ KERNELS=="input*", \
>     IMPORT{builtin}="hwdb 'libinput:name:$attr{name}:$attr{[dmi/id]modalias}'", \
>     GOTO="libinput_model_quirks_end"
>
> -
>   LABEL="libinput_model_quirks_end"
> diff --git a/udev/Makefile.am b/udev/Makefile.am
> index e5cf95c..e850e09 100644
> --- a/udev/Makefile.am
> +++ b/udev/Makefile.am
> @@ -1,5 +1,6 @@
>   udevdir=$(UDEV_DIR)
> -udev_PROGRAMS = libinput-device-group
> +udev_PROGRAMS = libinput-device-group \
> +		libinput-model-quirks
>
>   litest_rules = 80-libinput-device-groups-litest.rules \
>   	       90-libinput-model-quirks-litest.rules
> @@ -9,6 +10,13 @@ libinput_device_group_SOURCES = libinput-device-group.c
>   libinput_device_group_CFLAGS = $(LIBUDEV_CFLAGS) $(GCC_CFLAGS)
>   libinput_device_group_LDADD = $(LIBUDEV_LIBS)
>
> +libinput_model_quirks_SOURCES = libinput-model-quirks.c
> +libinput_model_quirks_CFLAGS = \
> +			       -I$(top_srcdir)/src \
> +			       $(LIBUDEV_CFLAGS) \
> +			       $(GCC_CFLAGS)
> +libinput_model_quirks_LDADD = $(LIBUDEV_LIBS)
> +
>   udev_rulesdir=$(UDEV_DIR)/rules.d
>   dist_udev_rules_DATA = \
>   	80-libinput-device-groups.rules \
> diff --git a/udev/libinput-model-quirks.c b/udev/libinput-model-quirks.c
> new file mode 100644
> index 0000000..87c19d4
> --- /dev/null
> +++ b/udev/libinput-model-quirks.c
> @@ -0,0 +1,146 @@
> +/*
> + * Copyright © 2015 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.
> + */
> +
> +#include "config.h"
> +
> +#include <fcntl.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <libudev.h>
> +#include <linux/input.h>
> +
> +#include "libinput-util.h"
> +
> +static inline const char *
> +prop_value(struct udev_device *device,
> +	   const char *prop_name)
> +{
> +	struct udev_device *parent;
> +	const char *prop_value = NULL;
> +
> +	parent = device;
> +	while (parent && !prop_value) {
> +		prop_value = udev_device_get_property_value(parent, prop_name);
> +		parent = udev_device_get_parent(parent);
> +	}
> +
> +	return prop_value;
> +}
> +
> +static void
> +handle_touchpad_elantech(struct udev_device *device)
> +{
> +	const char *devpath;
> +	int fd;
> +	unsigned int version = 0;
> +	struct input_absinfo absinfo;
> +	unsigned long props[NLONGS(INPUT_PROP_CNT)];
> +
> +	devpath = udev_device_get_devnode(device);
> +	fd = open(devpath, O_RDONLY|O_CLOEXEC);
> +	if (fd < 1)
> +		return;
> +
> +	/* Elantech v4: has resolution, we also assume that future versions
> +	 * will have resolution */
> +	if (ioctl(fd, EVIOCGABS(ABS_X), &absinfo) < 0)
> +		return;
> +
> +	if (absinfo.resolution != 0) {
> +		version = 4;
> +		goto out;
> +	}
> +
> +	if (ioctl(fd, EVIOCGPROP(sizeof(props)), props) < 0)
> +		goto out;
> +
> +	/* Elantech v3: always a buttonpad */
> +	if (long_bit_is_set(props, INPUT_PROP_BUTTONPAD)) {
> +		version = 3;
> +		goto out;
> +	}

This is not true, some older kernels used to do this, but itis wrong,
newer kernels have:

         case 2:
                 __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
                 __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
                 /* fall through */
         case 3:
                 if (etd->hw_version == 3)
                         elantech_set_buttonpad_prop(psmouse);

And:

static void elantech_set_buttonpad_prop(struct psmouse *psmouse)
{
         struct input_dev *dev = psmouse->dev;
         struct elantech_data *etd = psmouse->private;

         if (etd->fw_version & 0x001000) {
                 __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
                 __clear_bit(BTN_RIGHT, dev->keybit);
         }
}

Which dynamically detects if an elantech is a buttonpad or not,
and there are v3 devices out there of both variants.

Given the info we recently got from elantech that all <= v3
devices have a fixed resolution I guess we no longer need this.

I wonder if we should even bother handling this in userspace
for elantech devices at all. We can make the kernel driver
report the fixed resolution of for <= v3 device with a 1 line
kernel patch. I seem to have misplaced the mail from elantech with
the actual resolution, can you remind me what it was again ?

REgards,

Hans


More information about the wayland-devel mailing list