Hi Carlos, I think David was working on some similar problems recently, so maybe he has some comments on the overall approach?
Comment on the implementation: If you are going to add this tool to the systemd codebase, it would be better to do it as a bulit-in (calling out to binaries should only be done for third-party tools). Cheers, Tom On Thu, Dec 18, 2014 at 3:58 PM, Carlos Garnacho <carl...@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 <carl...@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)) { > + struct udev_device *device; > + const char *node; > + > + device = > udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate), > + > udev_list_entry_get_name(list_entry)); > + if (device == NULL) > + continue; > + /* Already found it */ > + if (devnode != NULL) { > + udev_device_unref(device); > + continue; > + } > + > + node = udev_device_get_devnode(device); > + if (node == NULL) { > + udev_device_unref(device); > + continue; > + } > + /* Use the event sub-device */ > + if (strstr(node, "/event") == NULL) { > + udev_device_unref(device); > + continue; > + } > + > + devnode = strdup(node); > + udev_device_unref(device); > + } > + > + if (devnode == NULL) { > + fprintf(stderr, "unable to get device node for '%s'\n", > devpath); > + return 0; > + } > + > + log_debug("Opening input device %s\n", devnode); > + extract_info(udev, dev, devnode); > + free(devnode); > + > + return 0; > +} > -- > 2.1.0 > > _______________________________________________ > systemd-devel mailing list > systemd-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/systemd-devel _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel