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

Reply via email to