[systemd-devel] [PATCH udev] udev: Add program/rule to export touchscreen/tablet size as udev properties

David Herrmann dh.herrmann at gmail.com
Thu Dec 18 07:22:15 PST 2014


Hi

On Thu, Dec 18, 2014 at 4:15 PM, David Herrmann <dh.herrmann at gmail.com> wrote:
> Hi
>
> On Thu, Dec 18, 2014 at 3:58 PM, Carlos Garnacho <carlosg at gnome.org> wrote:
>> This rule is only run on tablet/touchscreen devices, and extracts their size
>> in millimeters, as it can be found out through their struct input_absinfo.
>>
>> Conceivably, that information can be changed through EVIOCSABS anywhere
>> else, but we're only interested in values prior to any calibration, this
>> rule is thus only run on "add", and no tracking of changes is performed.
>> This should only remain a problem if calibration were automatically applied
>> by an earlier udev rule (read: don't).
>> ---
>>  Makefile.am                              |  14 +++
>>  rules/60-input_abs_size.rules            |   8 ++
>>  src/udev/input_abs_size/input_abs_size.c | 177 +++++++++++++++++++++++++++++++
>>  3 files changed, 199 insertions(+)
>>  create mode 100644 rules/60-input_abs_size.rules
>>  create mode 100644 src/udev/input_abs_size/input_abs_size.c
>>
>> diff --git a/Makefile.am b/Makefile.am
>> index ab07d3b..a23705a 100644
>> --- a/Makefile.am
>> +++ b/Makefile.am
>> @@ -3741,6 +3741,20 @@ dist_udevrules_DATA += \
>>         rules/61-accelerometer.rules
>>
>>  # ------------------------------------------------------------------------------
>> +input_abs_size_SOURCES = \
>> +       src/udev/input_abs_size/input_abs_size.c
>> +
>> +input_abs_size_LDADD = \
>> +       libudev-internal.la -lm \
>> +       libsystemd-shared.la
>> +
>> +udevlibexec_PROGRAMS += \
>> +       input_abs_size_
>> +
>> +dist_udevrules_DATA += \
>> +       rules/60-input_abs_size.rules
>> +
>> +# ------------------------------------------------------------------------------
>>  if ENABLE_GUDEV
>>  if ENABLE_GTK_DOC
>>  SUBDIRS += \
>> diff --git a/rules/60-input_abs_size.rules b/rules/60-input_abs_size.rules
>> new file mode 100644
>> index 0000000..5f613ac
>> --- /dev/null
>> +++ b/rules/60-input_abs_size.rules
>> @@ -0,0 +1,8 @@
>> +# do not edit this file, it will be overwritten on update
>> +
>> +ACTION!="add", GOTO="input_abs_size_end"
>> +
>> +ENV{ID_INPUT_TOUCHSCREEN}=="1", IMPORT{program}="input_abs_size %p"
>> +ENV{ID_INPUT_TABLET}=="1", IMPORT{program}="input_abs_size %p"
>> +
>> +LABEL="input_abs_size_end"
>> diff --git a/src/udev/input_abs_size/input_abs_size.c b/src/udev/input_abs_size/input_abs_size.c
>> new file mode 100644
>> index 0000000..34a6bf3
>> --- /dev/null
>> +++ b/src/udev/input_abs_size/input_abs_size.c
>> @@ -0,0 +1,177 @@
>> +/*
>> + * input_abs_size - extracts abs X/Y size in millimeters from input devices
>> + *
>> + * Copyright (C) 2014 Red Hat
>> + * Author:
>> + *   Carlos Garnacho  <carlosg at gnome.org>
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful, but
>> + * WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
>> + * General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with keymap; if not, write to the Free Software Foundation,
>> + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
>> + */
>> +
>> +#include <stdio.h>
>> +#include <string.h>
>> +#include <math.h>
>> +#include <sys/types.h>
>> +#include <sys/stat.h>
>> +#include <fcntl.h>
>> +#include <stdlib.h>
>> +#include <unistd.h>
>> +#include <getopt.h>
>> +#include <limits.h>
>> +#include <linux/limits.h>
>> +#include <linux/input.h>
>> +
>> +#include "libudev.h"
>> +#include "libudev-private.h"
>> +
>> +/* Resolution is defined to be in units/mm for ABS_X/Y */
>> +#define ABS_SIZE_MM(absinfo) ((absinfo.maximum - absinfo.minimum) / absinfo.resolution)
>> +
>> +static void extract_info(struct udev *udev,
>> +                         struct udev_device *dev,
>> +                         const char *devpath)
>> +{
>> +        struct input_absinfo xabsinfo = { 0 }, yabsinfo = { 0 };
>> +        _cleanup_close_ int fd = -1;
>> +        char text[1024];
>> +
>> +        if ((fd = open(devpath, O_RDONLY)) < 0)
>> +                return;
>> +
>> +        if (ioctl(fd, EVIOCGABS(ABS_X), &xabsinfo) < 0 ||
>> +            ioctl(fd, EVIOCGABS(ABS_Y), &yabsinfo) < 0)
>> +                return;
>> +
>> +        if (xabsinfo.resolution <= 0 || yabsinfo.resolution <= 0)
>> +                return;
>> +
>> +        snprintf (text, sizeof(text),
>> +                  "ID_INPUT_WIDTH_MM=%d\n"
>> +                  "ID_INPUT_HEIGHT_MM=%d",
>> +                  ABS_SIZE_MM (xabsinfo),
>> +                  ABS_SIZE_MM (yabsinfo));
>> +        puts (text);
>> +}
>> +
>> +static void help(void)
>> +{
>> +        printf("Usage: input_abs_size [options] <device path>\n"
>> +               "  --debug         debug to stderr\n"
>> +               "  --help          print this help text\n\n");
>> +}
>> +
>> +int main(int argc, char** argv)
>> +{
>> +        struct udev *udev;
>> +        struct udev_device *dev;
>> +
>> +        static const struct option options[] = {
>> +                { "debug", no_argument, NULL, 'd' },
>> +                { "help", no_argument, NULL, 'h' },
>> +                {}
>> +        };
>> +
>> +        char devpath[PATH_MAX];
>> +        char *devnode;
>> +        struct udev_enumerate *enumerate;
>> +        struct udev_list_entry *list_entry;
>> +
>> +        udev = udev_new();
>> +        if (udev == NULL)
>> +                return 1;
>> +
>> +        log_parse_environment();
>> +        log_open();
>> +
>> +        /* CLI argument parsing */
>> +        while (1) {
>> +                int option;
>> +
>> +                option = getopt_long(argc, argv, "dxh", options, NULL);
>> +                if (option == -1)
>> +                        break;
>> +
>> +                switch (option) {
>> +                case 'd':
>> +                        log_set_target(LOG_TARGET_CONSOLE);
>> +                        log_set_max_level(LOG_DEBUG);
>> +                        log_open();
>> +                        break;
>> +                case 'h':
>> +                        help();
>> +                        exit(0);
>> +                default:
>> +                        exit(1);
>> +                }
>> +        }
>> +
>> +        if (argv[optind] == NULL) {
>> +                help();
>> +                exit(1);
>> +        }
>> +
>> +        /* get the device */
>> +        snprintf(devpath, sizeof(devpath), "/sys/%s", argv[optind]);
>> +        dev = udev_device_new_from_syspath(udev, devpath);
>> +        if (dev == NULL) {
>> +                fprintf(stderr, "unable to access '%s'\n", devpath);
>> +                return 1;
>> +        }
>> +
>> +        /* Get the children devices and find the devnode */
>> +        devnode = NULL;
>> +        enumerate = udev_enumerate_new(udev);
>> +        udev_enumerate_add_match_parent(enumerate, dev);
>> +        udev_enumerate_scan_devices(enumerate);
>> +        udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) {
>
> Who guarantees that there are any children at the time you run this
> program? In fact, you run this program immediately once the input
> device is found, but the evdev device might get registered later. On
> modern machines, the kernel is fast enough to register both before any
> uevent can get scheduled. However, there is no such guarantee! I
> dislike relying on such races to not hit us..
>
> Regardless of that race: What is the point of exposing that
> information? Why would any process but a reader of the evdev device be
> interested in this? Your commit message lacks any explanation why this
> interface is useful. Please elaborate!

Ok, your head-letter includes that information. Could you merge that
into the commit-message on v2?

I'd recommend doing this whole thing as a built-in as Tom suggested
and then write those properties on the "eventXYZ" devices (the actual
evdev nodes). Everyone should be using those instead of the
input-device, so we should be fine.

Thanks
David


More information about the systemd-devel mailing list