/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include "libevdev.h" static void usage(void) { printf("%s --abs [--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 --on|--off /dev/input/eventXYZ\n" "\tEnable or disable the named LED\n", program_invocation_short_name, program_invocation_short_name); } enum mode { MODE_NONE = 0, MODE_ABS, MODE_LED, MODE_HELP, }; 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_abs(int argc, char **argv, unsigned int *changes, int *axis, struct input_absinfo *absinfo) { 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 }, { NULL, 0, 0, 0 }, }; if (argc < 2) goto error; optind = 1; while (1) { c = getopt_long(argc, argv, "h", opts, &option_index); if (c == -1) break; switch (c) { case OPT_ABS: *axis = libevdev_event_code_from_name(EV_ABS, optarg); if (*axis == -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; default: goto error; } *changes |= c; } rc = 0; error: return rc; } static int parse_options_led(int argc, char **argv, int *led, int *led_state) { int rc = 1; int c; int option_index = 0; static struct option opts[] = { { "led", 1, 0, OPT_LED }, { "on", 0, 0, OPT_ON }, { "off", 0, 0, OPT_OFF }, { NULL, 0, 0, 0 }, }; if (argc < 2) goto error; optind = 1; while (1) { c = getopt_long(argc, argv, "h", opts, &option_index); if (c == -1) break; switch (c) { case OPT_LED: *led = libevdev_event_code_from_name(EV_LED, optarg); if (*led == -1) goto error; 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; } } rc = 0; error: return rc; } static enum mode parse_options_mode(int argc, char **argv, const char **path) { int c; int option_index = 0; static const struct option opts[] = { { "abs", 1, 0, OPT_ABS }, { "led", 1, 0, OPT_LED }, { "help", 0, 0, OPT_HELP }, { NULL, 0, 0, 0 }, }; enum mode mode = MODE_NONE; if (argc < 2) return mode; while (1) { c = getopt_long(argc, argv, "h", opts, &option_index); if (c == -1) break; switch (c) { case 'h': case OPT_HELP: mode = MODE_HELP; break; case OPT_ABS: mode = MODE_ABS; break; case OPT_LED: mode = MODE_LED; break; default: break; } } if (optind >= argc) return MODE_NONE; *path = argv[optind]; return mode; } static void set_abs(struct libevdev *dev, unsigned int changes, unsigned int axis, struct input_absinfo *absinfo) { 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, unsigned int led, int led_state) { 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, led)); 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 = -1; int rc = 1; enum mode mode; const char *path; struct input_absinfo absinfo; int axis; int led; int led_state = -1; unsigned int changes; /* bitmask of changes */ mode = parse_options_mode(argc, argv, &path); switch (mode) { case MODE_HELP: rc = EXIT_SUCCESS; /* fallthrough */ case MODE_NONE: usage(); goto out; case MODE_ABS: rc = parse_options_abs(argc, argv, &changes, &axis, &absinfo); break; case MODE_LED: rc = parse_options_led(argc, argv, &led, &led_state); break; default: fprintf(stderr, "++?????++ Out of Cheese Error. Redo From Start.\n"); goto out; } if (rc != EXIT_SUCCESS) 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; } switch (mode) { case MODE_ABS: set_abs(dev, changes, axis, &absinfo); break; case MODE_LED: set_led(dev, led, led_state); break; default: break; } out: libevdev_free(dev); close(fd); return rc; }