diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2015-01-05 14:25:00 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2015-02-04 11:02:02 +1000 |
commit | 3bf7d50230958f8daaa7897ae948de78d1232998 (patch) | |
tree | 65177b81f19b42771d08e302f78d57f726a78219 /tools | |
parent | def17850d1f5ad3deb7262e67114135858928969 (diff) |
tools: add a tool to change kernel devices
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/.gitignore | 1 | ||||
-rw-r--r-- | tools/Makefile.am | 7 | ||||
-rw-r--r-- | tools/libevdev-tweak-device.1 | 59 | ||||
-rw-r--r-- | tools/libevdev-tweak-device.c | 255 |
4 files changed, 321 insertions, 1 deletions
diff --git a/tools/.gitignore b/tools/.gitignore index 292c08e..c2a2645 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -1,3 +1,4 @@ libevdev-events touchpad-edge-detector mouse-dpi-tool +libevdev-tweak-device diff --git a/tools/Makefile.am b/tools/Makefile.am index 8e3950d..d699c5c 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,7 +1,8 @@ noinst_PROGRAMS = libevdev-events bin_PROGRAMS = \ touchpad-edge-detector \ - mouse-dpi-tool + mouse-dpi-tool \ + libevdev-tweak-device AM_CPPFLAGS = $(GCC_CFLAGS) -I$(top_srcdir) -I$(top_srcdir)/include -I$(top_srcdir)/libevdev libevdev_ldadd = $(top_builddir)/libevdev/libevdev.la @@ -14,3 +15,7 @@ touchpad_edge_detector_LDADD = $(libevdev_ldadd) mouse_dpi_tool_SOURCES = mouse-dpi-tool.c mouse_dpi_tool_LDADD = $(libevdev_ldadd) + +libevdev_tweak_device_SOURCES = libevdev-tweak-device.c +libevdev_tweak_device_LDADD = $(libevdev_ldadd) +libevdev_tweak_device_MANS = libevdev-tweak-device.1 diff --git a/tools/libevdev-tweak-device.1 b/tools/libevdev-tweak-device.1 new file mode 100644 index 0000000..29f9a71 --- /dev/null +++ b/tools/libevdev-tweak-device.1 @@ -0,0 +1,59 @@ +.TH LIBEVDEV-TWEAK-DEVICE "1" +.SH NAME +libevdev-tweak-device \- modify an evdev kernel device +.SH SYNOPSIS +.B libevdev-tweak-device +--abs ABS_X [--min a] [--max b] [--res c] [--fuzz d] [--flat e] +/dev/input/eventX +.PP +.B libevdev-tweak-device +--led LED_NUML --on|--off /dev/input/eventX +.SH DESCRIPTION +.PP +The +.I libevdev-tweak-device +tool changes the properties of the evdev kernel device at +.I /dev/input/eventX. +Currently this may be used to force an LED on or off, or to change the +properties of an absolute axis (e.g. its minimum/maximum range or +resolution). Changes are permanent until the device is removed. +.SH OPTIONS +.SS Changing absolute axes +.TP 8 +.B --abs axis +Change the given named ABS_ kernel axis, e.g. ABS_X. For a full list, see linux/input.h. +Each of the options +.B min, max, res, fuzz, flat +may be given. +.TP 8 +.B --min v +Set the absinfo minimum to the value v +.TP 8 +.B --max v +Set the absinfo maximum to the value v +.TP 8 +.B --res v +Set the absinfo resolution to the value v +.TP 8 +.B --fuzz v +Set the absinfo fuzz to the value v +.TP 8 +.B --flat v +Set the absinfo flat to the value v +.PP +.SS Toggling LEDs +.TP 8 +.B --led led +Change the given LED, e.g. LED_NUML. For a full list, see linux/input.h. +.TP 8 +.B --on +Change the LED state to on +.TP 8 +.B --off +Change the LED state to off +.SH NOTES +.PP +The kernel does not notify processes about absinfo property changes. Any +process that has previously obtained the absinfo from the device will remain +on the old information. This makes using this tool potentially racy, use +with caution. diff --git a/tools/libevdev-tweak-device.c b/tools/libevdev-tweak-device.c new file mode 100644 index 0000000..a482d12 --- /dev/null +++ b/tools/libevdev-tweak-device.c @@ -0,0 +1,255 @@ +/* + * Copyright © 2014 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#define _GNU_SOURCE +#include <config.h> + +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <assert.h> +#include <linux/input.h> + +#include "libevdev.h" + +static unsigned int changes; /* bitmask of changes */ +static struct input_absinfo absinfo; +static int axis; +static int led; +static int led_state = -1; +const char *path; + +static void +usage(void) +{ + printf("%s --abs <axis> [--min min] [--max max] [--res res] [--fuzz fuzz] [--flat flat] /dev/input/eventXYZ\n" + "\tChange the absinfo struct for the named axis\n" + "%s --led <led> --on|--off /dev/input/eventXYZ\n" + "\tEnable or disable the named LED\n", + program_invocation_short_name, program_invocation_short_name); +} + +enum opts { + OPT_ABS = 1 << 0, + OPT_MIN = 1 << 1, + OPT_MAX = 1 << 2, + OPT_FUZZ = 1 << 3, + OPT_FLAT = 1 << 4, + OPT_RES = 1 << 5, + OPT_LED = 1 << 6, + OPT_ON = 1 << 7, + OPT_OFF = 1 << 8, + OPT_HELP = 1 << 9, +}; + +static int +parse_options(int argc, char **argv) +{ + int rc = 1; + int c; + int option_index = 0; + static struct option opts[] = { + { "abs", 1, 0, OPT_ABS }, + { "min", 1, 0, OPT_MIN }, + { "max", 1, 0, OPT_MAX }, + { "fuzz", 1, 0, OPT_FUZZ }, + { "flat", 1, 0, OPT_FLAT }, + { "res", 1, 0, OPT_RES }, + { "led", 1, 0, OPT_LED }, + { "on", 0, 0, OPT_ON }, + { "off", 0, 0, OPT_OFF }, + { "help", 0, 0, OPT_HELP }, + { NULL, 0, 0, 0 }, + }; + + if (argc < 2) + goto error; + + while (1) { + c = getopt_long(argc, argv, "h", opts, &option_index); + if (c == -1) + break; + + switch (c) { + case 'h': + case OPT_HELP: + goto error; + case OPT_ABS: + if (changes & OPT_LED) + goto error; + + axis = libevdev_event_code_from_name(EV_ABS, + optarg); + if (axis == -1) + goto error; + break; + case OPT_LED: + if (changes & OPT_ABS) + goto error; + + led = libevdev_event_code_from_name(EV_LED, + optarg); + if (led == -1) + goto error; + break; + case OPT_MIN: + absinfo.minimum = atoi(optarg); + break; + case OPT_MAX: + absinfo.maximum = atoi(optarg); + break; + case OPT_FUZZ: + absinfo.fuzz = atoi(optarg); + break; + case OPT_FLAT: + absinfo.flat = atoi(optarg); + break; + case OPT_RES: + absinfo.resolution = atoi(optarg); + break; + case OPT_ON: + if (led_state != -1) + goto error; + led_state = 1; + break; + case OPT_OFF: + if (led_state != -1) + goto error; + led_state = 0; + break; + default: + goto error; + } + changes |= c; + } + + if (optind >= argc) + goto error; + path = argv[optind]; + + rc = 0; +error: + return rc; +} + +static void +set_abs(struct libevdev *dev) +{ + int rc; + struct input_absinfo abs; + const struct input_absinfo *a; + + if ((a = libevdev_get_abs_info(dev, axis)) == NULL) { + fprintf(stderr, + "Device '%s' doesn't have axis %s\n", + libevdev_get_name(dev), + libevdev_event_code_get_name(EV_ABS, axis)); + return; + } + + abs = *a; + if (changes & OPT_MIN) + abs.minimum = absinfo.minimum; + if (changes & OPT_MAX) + abs.maximum = absinfo.maximum; + if (changes & OPT_FUZZ) + abs.fuzz = absinfo.fuzz; + if (changes & OPT_FLAT) + abs.flat = absinfo.flat; + if (changes & OPT_RES) + abs.resolution = absinfo.resolution; + + rc = libevdev_kernel_set_abs_info(dev, axis, &abs); + if (rc != 0) + fprintf(stderr, + "Failed to set absinfo %s: %s", + libevdev_event_code_get_name(EV_ABS, axis), + strerror(-rc)); +} + +static void +set_led(struct libevdev *dev) +{ + int rc; + enum libevdev_led_value state = + led_state ? LIBEVDEV_LED_ON : LIBEVDEV_LED_OFF; + + if (!libevdev_has_event_code(dev, EV_LED, led)) { + fprintf(stderr, + "Device '%s' doesn't have %s\n", + libevdev_get_name(dev), + libevdev_event_code_get_name(EV_LED, axis)); + return; + } + + + rc = libevdev_kernel_set_led_value(dev, led, state); + if (rc != 0) + fprintf(stderr, + "Failed to set LED %s: %s", + libevdev_event_code_get_name(EV_LED, led), + strerror(-rc)); +} + +int +main(int argc, char **argv) +{ + struct libevdev *dev = NULL; + int fd; + int rc = 1; + + rc = parse_options(argc, argv); + if (rc != 0 || !path) { + usage(); + goto out; + } + + fd = open(path, O_RDWR); + if (fd < 0) { + perror("Failed to open device"); + goto out; + } + + rc = libevdev_new_from_fd(fd, &dev); + if (rc < 0) { + fprintf(stderr, "Failed to init libevdev (%s)\n", strerror(-rc)); + goto out; + } + + if (changes & OPT_ABS) + set_abs(dev); + else if (changes & OPT_LED) + set_led(dev); + else + fprintf(stderr, + "++?????++ Out of Cheese Error. Redo From Start.\n"); + +out: + libevdev_free(dev); + + return rc; +} |