mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-20 16:10:06 +01:00
udev: parse the EVDEV_ABS properties for a potential fuzz setting
Where a fuzz is defined in the 60-evdev.hwdb, we rely on a udev builtin to
set the kernel device to that fuzz value. Unfortunately that happens after our
program is called with this order of events:
1. 60-evdev.rules calls IMPORT(builtin) for the hwdb which sets the EVDEV_ABS_*
properties. It also sets RUN{builtin}=keyboard but that's not invoked yet.
2. 90-libinput-fuzz-override.rules calls IMPORT{program} for our fuzz override
bits. That sets the kernel fuzz value to 0 and sets the LIBINPUT_FUZZ_*
propertie
3. The keyboard builtin is run once all the rules have been processed.
Our problem is that where the fuzz is set in a hwdb entry, the kernel fuzz is
still unset when we get to look at it, so we always end up with a fuzz of zero
for us and a nonzero kernel fuzz.
Work around this by checking the EVDEV_ABS property, extracting the fuzz from
there and re-printing that property without the fuzz. This way we ensure the
kernel remains at zero fuzz and we use the one from the hwdb instead.
Fixes #346
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
1e6802b91b
commit
e7a9c07ffe
8 changed files with 459 additions and 18 deletions
12
meson.build
12
meson.build
|
|
@ -149,8 +149,16 @@ executable('libinput-device-group',
|
||||||
include_directories : [includes_src, includes_include],
|
include_directories : [includes_src, includes_include],
|
||||||
install : true,
|
install : true,
|
||||||
install_dir : dir_udev_callouts)
|
install_dir : dir_udev_callouts)
|
||||||
executable('libinput-fuzz-override',
|
executable('libinput-fuzz-extract',
|
||||||
'udev/libinput-fuzz-override.c',
|
'udev/libinput-fuzz-extract.c',
|
||||||
|
'src/util-strings.c',
|
||||||
|
'src/util-prop-parsers.c',
|
||||||
|
dependencies : [dep_udev, dep_libevdev, dep_lm],
|
||||||
|
include_directories : [includes_src, includes_include],
|
||||||
|
install : true,
|
||||||
|
install_dir : dir_udev_callouts)
|
||||||
|
executable('libinput-fuzz-to-zero',
|
||||||
|
'udev/libinput-fuzz-to-zero.c',
|
||||||
dependencies : [dep_udev, dep_libevdev],
|
dependencies : [dep_udev, dep_libevdev],
|
||||||
include_directories : [includes_src, includes_include],
|
include_directories : [includes_src, includes_include],
|
||||||
install : true,
|
install : true,
|
||||||
|
|
|
||||||
|
|
@ -401,3 +401,70 @@ out:
|
||||||
strv_free(strv);
|
strv_free(strv);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the property value for the EVDEV_ABS_00 properties. Spec is
|
||||||
|
* EVDEV_ABS_00=min:max:res:fuzz:flat
|
||||||
|
* where any element may be empty and subsequent elements may not be
|
||||||
|
* present. So we have to parse
|
||||||
|
* EVDEV_ABS_00=min:max:res
|
||||||
|
* EVDEV_ABS_00=::res
|
||||||
|
* EVDEV_ABS_00=::res:fuzz:
|
||||||
|
*
|
||||||
|
* Returns a mask of the bits set and the absinfo struct with the values.
|
||||||
|
* The abs value for an unset bit is undefined.
|
||||||
|
*/
|
||||||
|
uint32_t
|
||||||
|
parse_evdev_abs_prop(const char *prop, struct input_absinfo *abs)
|
||||||
|
{
|
||||||
|
char *str = strdup(prop);
|
||||||
|
char *current, *next;
|
||||||
|
uint32_t mask = 0;
|
||||||
|
int bit = ABS_MASK_MIN;
|
||||||
|
int *val;
|
||||||
|
int values[5];
|
||||||
|
|
||||||
|
/* basic sanity check: 5 digits for min/max, 3 for resolution, fuzz,
|
||||||
|
* flat and the colons. That's plenty, anything over is garbage */
|
||||||
|
if (strlen(prop) > 24)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
current = str;
|
||||||
|
val = values;
|
||||||
|
while (current && *current != '\0' && bit <= ABS_MASK_FLAT) {
|
||||||
|
if (*current != ':') {
|
||||||
|
int v;
|
||||||
|
next = index(current, ':');
|
||||||
|
if (next)
|
||||||
|
*next = '\0';
|
||||||
|
|
||||||
|
if (!safe_atoi(current, &v)) {
|
||||||
|
mask = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
*val = v;
|
||||||
|
mask |= bit;
|
||||||
|
current = next ? ++next : NULL;
|
||||||
|
} else {
|
||||||
|
current++;
|
||||||
|
}
|
||||||
|
bit <<= 1;
|
||||||
|
val++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask & ABS_MASK_MIN)
|
||||||
|
abs->minimum = values[0];
|
||||||
|
if (mask & ABS_MASK_MAX)
|
||||||
|
abs->maximum = values[1];
|
||||||
|
if (mask & ABS_MASK_RES)
|
||||||
|
abs->resolution = values[2];
|
||||||
|
if (mask & ABS_MASK_FUZZ)
|
||||||
|
abs->fuzz = values[3];
|
||||||
|
if (mask & ABS_MASK_FLAT)
|
||||||
|
abs->flat = values[4];
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(str);
|
||||||
|
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
int parse_mouse_dpi_property(const char *prop);
|
int parse_mouse_dpi_property(const char *prop);
|
||||||
int parse_mouse_wheel_click_angle_property(const char *prop);
|
int parse_mouse_wheel_click_angle_property(const char *prop);
|
||||||
|
|
@ -54,3 +55,13 @@ enum switch_reliability {
|
||||||
bool
|
bool
|
||||||
parse_switch_reliability_property(const char *prop,
|
parse_switch_reliability_property(const char *prop,
|
||||||
enum switch_reliability *reliability);
|
enum switch_reliability *reliability);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ABS_MASK_MIN = 0x1,
|
||||||
|
ABS_MASK_MAX = 0x2,
|
||||||
|
ABS_MASK_RES = 0x4,
|
||||||
|
ABS_MASK_FUZZ = 0x8,
|
||||||
|
ABS_MASK_FLAT = 0x10,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t parse_evdev_abs_prop(const char *prop, struct input_absinfo *abs);
|
||||||
|
|
|
||||||
|
|
@ -546,6 +546,83 @@ START_TEST(evcode_prop_parser)
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(evdev_abs_parser)
|
||||||
|
{
|
||||||
|
struct test {
|
||||||
|
uint32_t which;
|
||||||
|
const char *prop;
|
||||||
|
int min, max, res, fuzz, flat;
|
||||||
|
|
||||||
|
} tests[] = {
|
||||||
|
{ .which = (ABS_MASK_MIN|ABS_MASK_MAX),
|
||||||
|
.prop = "1:2",
|
||||||
|
.min = 1, .max = 2 },
|
||||||
|
{ .which = (ABS_MASK_MIN|ABS_MASK_MAX),
|
||||||
|
.prop = "1:2:",
|
||||||
|
.min = 1, .max = 2 },
|
||||||
|
{ .which = (ABS_MASK_MIN|ABS_MASK_MAX|ABS_MASK_RES),
|
||||||
|
.prop = "10:20:30",
|
||||||
|
.min = 10, .max = 20, .res = 30 },
|
||||||
|
{ .which = (ABS_MASK_RES),
|
||||||
|
.prop = "::100",
|
||||||
|
.res = 100 },
|
||||||
|
{ .which = (ABS_MASK_MIN),
|
||||||
|
.prop = "10:",
|
||||||
|
.min = 10 },
|
||||||
|
{ .which = (ABS_MASK_MAX|ABS_MASK_RES),
|
||||||
|
.prop = ":10:1001",
|
||||||
|
.max = 10, .res = 1001 },
|
||||||
|
{ .which = (ABS_MASK_MIN|ABS_MASK_MAX|ABS_MASK_RES|ABS_MASK_FUZZ),
|
||||||
|
.prop = "1:2:3:4",
|
||||||
|
.min = 1, .max = 2, .res = 3, .fuzz = 4},
|
||||||
|
{ .which = (ABS_MASK_MIN|ABS_MASK_MAX|ABS_MASK_RES|ABS_MASK_FUZZ|ABS_MASK_FLAT),
|
||||||
|
.prop = "1:2:3:4:5",
|
||||||
|
.min = 1, .max = 2, .res = 3, .fuzz = 4, .flat = 5},
|
||||||
|
{ .which = (ABS_MASK_MIN|ABS_MASK_RES|ABS_MASK_FUZZ|ABS_MASK_FLAT),
|
||||||
|
.prop = "1::3:4:50",
|
||||||
|
.min = 1, .res = 3, .fuzz = 4, .flat = 50},
|
||||||
|
{ .which = ABS_MASK_FUZZ|ABS_MASK_FLAT,
|
||||||
|
.prop = ":::5:60",
|
||||||
|
.fuzz = 5, .flat = 60},
|
||||||
|
{ .which = ABS_MASK_FUZZ,
|
||||||
|
.prop = ":::5:",
|
||||||
|
.fuzz = 5 },
|
||||||
|
{ .which = ABS_MASK_RES, .prop = "::12::",
|
||||||
|
.res = 12 },
|
||||||
|
/* Malformed property but parsing this one makes us more
|
||||||
|
* future proof */
|
||||||
|
{ .which = (ABS_MASK_RES|ABS_MASK_FUZZ|ABS_MASK_FLAT),
|
||||||
|
.prop = "::12:1:2:3:4:5:6",
|
||||||
|
.res = 12, .fuzz = 1, .flat = 2 },
|
||||||
|
{ .which = 0, .prop = ":::::" },
|
||||||
|
{ .which = 0, .prop = ":" },
|
||||||
|
{ .which = 0, .prop = "" },
|
||||||
|
{ .which = 0, .prop = ":asb::::" },
|
||||||
|
{ .which = 0, .prop = "foo" },
|
||||||
|
};
|
||||||
|
struct test *t;
|
||||||
|
|
||||||
|
ARRAY_FOR_EACH(tests, t) {
|
||||||
|
struct input_absinfo abs;
|
||||||
|
uint32_t mask;
|
||||||
|
|
||||||
|
mask = parse_evdev_abs_prop(t->prop, &abs);
|
||||||
|
ck_assert_int_eq(mask, t->which);
|
||||||
|
|
||||||
|
if (t->which & ABS_MASK_MIN)
|
||||||
|
ck_assert_int_eq(abs.minimum, t->min);
|
||||||
|
if (t->which & ABS_MASK_MAX)
|
||||||
|
ck_assert_int_eq(abs.maximum, t->max);
|
||||||
|
if (t->which & ABS_MASK_RES)
|
||||||
|
ck_assert_int_eq(abs.resolution, t->res);
|
||||||
|
if (t->which & ABS_MASK_FUZZ)
|
||||||
|
ck_assert_int_eq(abs.fuzz, t->fuzz);
|
||||||
|
if (t->which & ABS_MASK_FLAT)
|
||||||
|
ck_assert_int_eq(abs.flat, t->flat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
START_TEST(time_conversion)
|
START_TEST(time_conversion)
|
||||||
{
|
{
|
||||||
ck_assert_int_eq(us(10), 10);
|
ck_assert_int_eq(us(10), 10);
|
||||||
|
|
@ -1050,6 +1127,7 @@ litest_utils_suite(void)
|
||||||
tcase_add_test(tc, calibration_prop_parser);
|
tcase_add_test(tc, calibration_prop_parser);
|
||||||
tcase_add_test(tc, range_prop_parser);
|
tcase_add_test(tc, range_prop_parser);
|
||||||
tcase_add_test(tc, evcode_prop_parser);
|
tcase_add_test(tc, evcode_prop_parser);
|
||||||
|
tcase_add_test(tc, evdev_abs_parser);
|
||||||
tcase_add_test(tc, safe_atoi_test);
|
tcase_add_test(tc, safe_atoi_test);
|
||||||
tcase_add_test(tc, safe_atoi_base_16_test);
|
tcase_add_test(tc, safe_atoi_base_16_test);
|
||||||
tcase_add_test(tc, safe_atoi_base_8_test);
|
tcase_add_test(tc, safe_atoi_base_8_test);
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,22 @@
|
||||||
ACTION!="add|change", GOTO="libinput_fuzz_override_end"
|
ACTION!="add|change", GOTO="libinput_fuzz_override_end"
|
||||||
KERNEL!="event*", GOTO="libinput_fuzz_override_end"
|
KERNEL!="event*", GOTO="libinput_fuzz_override_end"
|
||||||
|
|
||||||
# libinput-fuzz-override must only be called once per device, otherwise
|
# Two-step process: fuzz-extract sets the LIBINPUT_FUZZ property and
|
||||||
# we'll lose the fuzz information
|
# fuzz-to-zero sets the kernel fuzz to zero. They must be in IMPORT and RUN,
|
||||||
|
# respectively, to correctly interact with the 60-evdev.hwdb
|
||||||
|
#
|
||||||
|
# Drawback: if this rule is triggered more than once, we'll lose the fuzz
|
||||||
|
# information (because the kernel fuzz will then be zero). Nothing we can do
|
||||||
|
# about that.
|
||||||
ATTRS{capabilities/abs}!="0", \
|
ATTRS{capabilities/abs}!="0", \
|
||||||
ENV{ID_INPUT_TOUCHPAD}=="1", \
|
ENV{ID_INPUT_TOUCHPAD}=="1", \
|
||||||
IMPORT{program}="@UDEV_TEST_PATH@libinput-fuzz-override %S%p", \
|
IMPORT{program}="@UDEV_TEST_PATH@libinput-fuzz-extract %S%p", \
|
||||||
|
RUN{program}="@UDEV_TEST_PATH@libinput-fuzz-to-zero %S%p", \
|
||||||
GOTO="libinput_fuzz_override_end"
|
GOTO="libinput_fuzz_override_end"
|
||||||
ATTRS{capabilities/abs}!="0", \
|
ATTRS{capabilities/abs}!="0", \
|
||||||
ENV{ID_INPUT_TOUCHSCREEN}=="1", \
|
ENV{ID_INPUT_TOUCHSCREEN}=="1", \
|
||||||
IMPORT{program}="@UDEV_TEST_PATH@libinput-fuzz-override %S%p", \
|
IMPORT{program}="@UDEV_TEST_PATH@libinput-fuzz-extract %S%p", \
|
||||||
|
RUN{program}="@UDEV_TEST_PATH@libinput-fuzz-to-zero %S%p", \
|
||||||
GOTO="libinput_fuzz_override_end"
|
GOTO="libinput_fuzz_override_end"
|
||||||
|
|
||||||
LABEL="libinput_fuzz_override_end"
|
LABEL="libinput_fuzz_override_end"
|
||||||
|
|
|
||||||
150
udev/libinput-fuzz-extract.c
Normal file
150
udev/libinput-fuzz-extract.c
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2015 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <libudev.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <libevdev/libevdev.h>
|
||||||
|
|
||||||
|
#include "util-prop-parsers.h"
|
||||||
|
#include "util-macros.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For a non-zero fuzz on the x/y axes, print that fuzz as property and
|
||||||
|
* reset the kernel's fuzz to 0.
|
||||||
|
* https://bugs.freedesktop.org/show_bug.cgi?id=105202
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
handle_absfuzz(struct udev_device *device)
|
||||||
|
{
|
||||||
|
const char *devnode;
|
||||||
|
struct libevdev *evdev = NULL;
|
||||||
|
int fd = -1;
|
||||||
|
int rc;
|
||||||
|
unsigned int *code;
|
||||||
|
unsigned int axes[] = {ABS_X,
|
||||||
|
ABS_Y,
|
||||||
|
ABS_MT_POSITION_X,
|
||||||
|
ABS_MT_POSITION_Y};
|
||||||
|
|
||||||
|
devnode = udev_device_get_devnode(device);
|
||||||
|
if (!devnode)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
fd = open(devnode, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
rc = libevdev_new_from_fd(fd, &evdev);
|
||||||
|
if (rc != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!libevdev_has_event_type(evdev, EV_ABS))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ARRAY_FOR_EACH(axes, code) {
|
||||||
|
int fuzz;
|
||||||
|
|
||||||
|
fuzz = libevdev_get_abs_fuzz(evdev, *code);
|
||||||
|
if (fuzz)
|
||||||
|
printf("LIBINPUT_FUZZ_%02x=%d\n", *code, fuzz);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
close(fd);
|
||||||
|
libevdev_free(evdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where a device has EVDEV_ABS_... set with a fuzz, that fuzz hasn't been
|
||||||
|
* applied to the kernel yet. So we need to extract it ourselves **and**
|
||||||
|
* update the property so the kernel won't actually set it later.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
handle_evdev_abs(struct udev_device *device)
|
||||||
|
{
|
||||||
|
unsigned int *code;
|
||||||
|
unsigned int axes[] = {ABS_X,
|
||||||
|
ABS_Y,
|
||||||
|
ABS_MT_POSITION_X,
|
||||||
|
ABS_MT_POSITION_Y};
|
||||||
|
|
||||||
|
ARRAY_FOR_EACH(axes, code) {
|
||||||
|
const char *prop;
|
||||||
|
char name[64];
|
||||||
|
uint32_t mask;
|
||||||
|
struct input_absinfo abs;
|
||||||
|
|
||||||
|
snprintf(name, sizeof(name), "EVDEV_ABS_%02X", *code);
|
||||||
|
prop = udev_device_get_property_value(device, name);
|
||||||
|
if (!prop)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mask = parse_evdev_abs_prop(prop, &abs);
|
||||||
|
if (mask & ABS_MASK_FUZZ)
|
||||||
|
printf("LIBINPUT_FUZZ_%02x=%d\n", *code, abs.fuzz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int rc = 1;
|
||||||
|
struct udev *udev = NULL;
|
||||||
|
struct udev_device *device = NULL;
|
||||||
|
const char *syspath;
|
||||||
|
|
||||||
|
if (argc != 2)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
syspath = argv[1];
|
||||||
|
|
||||||
|
udev = udev_new();
|
||||||
|
if (!udev)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
device = udev_device_new_from_syspath(udev, syspath);
|
||||||
|
if (!device)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
handle_absfuzz(device);
|
||||||
|
handle_evdev_abs(device);
|
||||||
|
|
||||||
|
rc = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (device)
|
||||||
|
udev_device_unref(device);
|
||||||
|
if (udev)
|
||||||
|
udev_unref(udev);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
@ -27,21 +27,19 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <libudev.h>
|
#include <libudev.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <libevdev/libevdev.h>
|
#include <libevdev/libevdev.h>
|
||||||
|
|
||||||
#include "libinput-util.h"
|
#include "util-strings.h"
|
||||||
|
#include "util-macros.h"
|
||||||
|
#include "util-bits.h"
|
||||||
|
|
||||||
/**
|
|
||||||
* For a non-zero fuzz on the x/y axes, print that fuzz as property and
|
|
||||||
* reset the kernel's fuzz to 0.
|
|
||||||
* https://bugs.freedesktop.org/show_bug.cgi?id=105202
|
|
||||||
*/
|
|
||||||
static void
|
static void
|
||||||
handle_absfuzz(struct udev_device *device)
|
reset_absfuzz_to_zero(struct udev_device *device)
|
||||||
{
|
{
|
||||||
const char *devnode;
|
const char *devnode;
|
||||||
struct libevdev *evdev = NULL;
|
struct libevdev *evdev = NULL;
|
||||||
|
|
@ -58,8 +56,6 @@ handle_absfuzz(struct udev_device *device)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
fd = open(devnode, O_RDWR);
|
fd = open(devnode, O_RDWR);
|
||||||
if (fd == -1 && errno == EACCES)
|
|
||||||
fd = open(devnode, O_RDONLY);
|
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
@ -81,8 +77,6 @@ handle_absfuzz(struct udev_device *device)
|
||||||
abs = *libevdev_get_abs_info(evdev, *code);
|
abs = *libevdev_get_abs_info(evdev, *code);
|
||||||
abs.fuzz = 0;
|
abs.fuzz = 0;
|
||||||
libevdev_kernel_set_abs_info(evdev, *code, &abs);
|
libevdev_kernel_set_abs_info(evdev, *code, &abs);
|
||||||
|
|
||||||
printf("LIBINPUT_FUZZ_%02x=%d\n", *code, fuzz);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
@ -110,7 +104,7 @@ int main(int argc, char **argv)
|
||||||
if (!device)
|
if (!device)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
handle_absfuzz(device);
|
reset_absfuzz_to_zero(device);
|
||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
|
||||||
126
udev/test-libinput-fuzz-extract.c
Normal file
126
udev/test-libinput-fuzz-extract.c
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2019 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <check.h>
|
||||||
|
|
||||||
|
/* remove the main() from the included program so we can define our own */
|
||||||
|
#define main __disabled
|
||||||
|
int main(int argc, char **argv);
|
||||||
|
#include "libinput-fuzz-extract.c"
|
||||||
|
#undef main
|
||||||
|
|
||||||
|
START_TEST(test_parse_ev_abs)
|
||||||
|
{
|
||||||
|
struct test {
|
||||||
|
uint32_t which;
|
||||||
|
const char *prop;
|
||||||
|
int min, max, res, fuzz, flat;
|
||||||
|
|
||||||
|
} tests[] = {
|
||||||
|
{ .which = (MIN|MAX),
|
||||||
|
.prop = "1:2",
|
||||||
|
.min = 1, .max = 2 },
|
||||||
|
{ .which = (MIN|MAX),
|
||||||
|
.prop = "1:2:",
|
||||||
|
.min = 1, .max = 2 },
|
||||||
|
{ .which = (MIN|MAX|RES),
|
||||||
|
.prop = "10:20:30",
|
||||||
|
.min = 10, .max = 20, .res = 30 },
|
||||||
|
{ .which = (RES),
|
||||||
|
.prop = "::100",
|
||||||
|
.res = 100 },
|
||||||
|
{ .which = (MIN),
|
||||||
|
.prop = "10:",
|
||||||
|
.min = 10 },
|
||||||
|
{ .which = (MAX|RES),
|
||||||
|
.prop = ":10:1001",
|
||||||
|
.max = 10, .res = 1001 },
|
||||||
|
{ .which = (MIN|MAX|RES|FUZZ),
|
||||||
|
.prop = "1:2:3:4",
|
||||||
|
.min = 1, .max = 2, .res = 3, .fuzz = 4},
|
||||||
|
{ .which = (MIN|MAX|RES|FUZZ|FLAT),
|
||||||
|
.prop = "1:2:3:4:5",
|
||||||
|
.min = 1, .max = 2, .res = 3, .fuzz = 4, .flat = 5},
|
||||||
|
{ .which = (MIN|RES|FUZZ|FLAT),
|
||||||
|
.prop = "1::3:4:50",
|
||||||
|
.min = 1, .res = 3, .fuzz = 4, .flat = 50},
|
||||||
|
{ .which = FUZZ|FLAT,
|
||||||
|
.prop = ":::5:60",
|
||||||
|
.fuzz = 5, .flat = 60},
|
||||||
|
{ .which = FUZZ,
|
||||||
|
.prop = ":::5:",
|
||||||
|
.fuzz = 5 },
|
||||||
|
{ .which = RES, .prop = "::12::",
|
||||||
|
.res = 12 },
|
||||||
|
/* Malformed property but parsing this one makes us more
|
||||||
|
* future proof */
|
||||||
|
{ .which = (RES|FUZZ|FLAT), .prop = "::12:1:2:3:4:5:6",
|
||||||
|
.res = 12, .fuzz = 1, .flat = 2 },
|
||||||
|
{ .which = 0, .prop = ":::::" },
|
||||||
|
{ .which = 0, .prop = ":" },
|
||||||
|
{ .which = 0, .prop = "" },
|
||||||
|
{ .which = 0, .prop = ":asb::::" },
|
||||||
|
{ .which = 0, .prop = "foo" },
|
||||||
|
};
|
||||||
|
struct test *t;
|
||||||
|
|
||||||
|
ARRAY_FOR_EACH(tests, t) {
|
||||||
|
struct input_absinfo abs;
|
||||||
|
uint32_t mask;
|
||||||
|
|
||||||
|
mask = parse_ev_abs_prop(t->prop, &abs);
|
||||||
|
ck_assert_int_eq(mask, t->which);
|
||||||
|
|
||||||
|
if (t->which & MIN)
|
||||||
|
ck_assert_int_eq(abs.minimum, t->min);
|
||||||
|
if (t->which & MAX)
|
||||||
|
ck_assert_int_eq(abs.maximum, t->max);
|
||||||
|
if (t->which & RES)
|
||||||
|
ck_assert_int_eq(abs.resolution, t->res);
|
||||||
|
if (t->which & FUZZ)
|
||||||
|
ck_assert_int_eq(abs.fuzz, t->fuzz);
|
||||||
|
if (t->which & FLAT)
|
||||||
|
ck_assert_int_eq(abs.flat, t->flat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
|
||||||
|
SRunner *sr = srunner_create(NULL);
|
||||||
|
Suite *s = suite_create("fuzz-override");
|
||||||
|
TCase *tc = tcase_create("parser");
|
||||||
|
int nfailed;
|
||||||
|
|
||||||
|
tcase_add_test(tc, test_parse_ev_abs);
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
srunner_add_suite(sr, s);
|
||||||
|
|
||||||
|
srunner_run_all(sr, CK_NORMAL);
|
||||||
|
nfailed = srunner_ntests_failed(sr);
|
||||||
|
srunner_free(sr);
|
||||||
|
|
||||||
|
return nfailed;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue