From 145e2c814fbf50fb1d0193da90fb947945f5e78e Mon Sep 17 00:00:00 2001 From: illiliti Date: Tue, 25 May 2021 15:34:24 +0300 Subject: [PATCH] udev_device.c: attempt to fix incorrect bitmask handling Reference #22 --- udev_device.c | 108 ++++++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 56 deletions(-) diff --git a/udev_device.c b/udev_device.c index b487fd3..1ccd566 100644 --- a/udev_device.c +++ b/udev_device.c @@ -9,7 +9,17 @@ #include "udev.h" #include "udev_list.h" -#define BITS_MAX 96 +// sizeof(unsigned long) == 4 * 8 == 32 on 32-bit systems. +// sizeof(unsigned long) == 8 * 8 == 64 on 64-bit systems. +#ifndef LONG_BIT +#define LONG_BIT (sizeof(unsigned long) * 8) +#endif + +// https://www.kernel.org/doc/html/latest/input/ff.html#querying-device-capabilities +// https://www.kernel.org/doc/html/latest/input/input-programming.html#bits-to-longs-bit-word-bit-mask +#define BIT_WORD(x) ((x) / LONG_BIT) +#define BIT_MASK(x) (1UL << ((x) % LONG_BIT)) +#define BITS_TO_LONGS(x) (((x) + LONG_BIT - 1) / LONG_BIT) #ifndef INPUT_PROP_POINTING_STICK #define INPUT_PROP_POINTING_STICK 0x05 @@ -338,51 +348,37 @@ static void udev_device_set_properties_from_uevent(struct udev_device *udev_devi fclose(file); } -static int populate_bit(unsigned long *arr, const char *str) +static void make_bit(unsigned long *arr, int cnt, const char *str) { - char *beg, *end; + size_t len; int i; if (!str) { - return 0; + return; } - // TODO drop strdup ? - beg = end = strdup(str); - - if (!beg) { - return 0; - } - - for (i = 0; end[0] != '\0' && i < BITS_MAX; i++) { - arr[i] = strtoul(end, &end, 16); - } - - free(beg); - return i; -} - -static int find_bit(unsigned long *arr, int cnt, unsigned long bit) -{ - int i; - - for (i = 0; i < cnt; i++) { - if (arr[i] & (1UL << (bit % LONG_BIT))) { - return 1; + for (i = 0, len = strlen(str); i < cnt && len > 0; len--) { + if (str[len] == ' ') { + arr[i++] = strtoul(str + len + 1, NULL, 16); } } - return 0; + arr[i] = strtoul(str, NULL, 16); +} + +static int test_bit(unsigned long *arr, unsigned long bit) +{ + return arr[BIT_WORD(bit)] & BIT_MASK(bit); } static void udev_device_set_properties_from_evdev(struct udev_device *udev_device) { - int ev_cnt, rel_cnt, key_cnt, abs_cnt, prop_cnt; - unsigned long prop_bits[BITS_MAX] = {0}; - unsigned long abs_bits[BITS_MAX] = {0}; - unsigned long rel_bits[BITS_MAX] = {0}; - unsigned long key_bits[BITS_MAX] = {0}; - unsigned long ev_bits[BITS_MAX] = {0}; + // https://www.kernel.org/doc/html/latest/driver-api/input.html#c.input_dev + unsigned long prop_bits[BITS_TO_LONGS(INPUT_PROP_CNT)] = {0}; + unsigned long abs_bits[BITS_TO_LONGS(ABS_CNT)] = {0}; + unsigned long rel_bits[BITS_TO_LONGS(REL_CNT)] = {0}; + unsigned long key_bits[BITS_TO_LONGS(KEY_CNT)] = {0}; + unsigned long ev_bits[BITS_TO_LONGS(EV_CNT)] = {0}; struct udev_device *parent; const char *subsystem; @@ -406,67 +402,67 @@ static void udev_device_set_properties_from_evdev(struct udev_device *udev_devic parent = udev_device_get_parent_with_subsystem_devtype(parent, "input", NULL); } - ev_cnt = populate_bit(ev_bits, udev_device_get_property_value(parent, "EV")); - abs_cnt = populate_bit(abs_bits, udev_device_get_property_value(parent, "ABS")); - rel_cnt = populate_bit(rel_bits, udev_device_get_property_value(parent, "REL")); - key_cnt = populate_bit(key_bits, udev_device_get_property_value(parent, "KEY")); - prop_cnt = populate_bit(prop_bits, udev_device_get_property_value(parent, "PROP")); + make_bit(ev_bits, sizeof(ev_bits) / sizeof(ev_bits[0]), udev_device_get_property_value(parent, "EV")); + make_bit(abs_bits, sizeof(abs_bits) / sizeof(abs_bits[0]), udev_device_get_property_value(parent, "ABS")); + make_bit(rel_bits, sizeof(rel_bits) / sizeof(rel_bits[0]), udev_device_get_property_value(parent, "REL")); + make_bit(key_bits, sizeof(key_bits) / sizeof(key_bits[0]), udev_device_get_property_value(parent, "KEY")); + make_bit(prop_bits, sizeof(prop_bits) / sizeof(prop_bits[0]), udev_device_get_property_value(parent, "PROP")); udev_list_entry_add(&udev_device->properties, "ID_INPUT", "1", 0); - if (find_bit(prop_bits, prop_cnt, INPUT_PROP_POINTING_STICK)) { + if (test_bit(prop_bits, INPUT_PROP_POINTING_STICK)) { udev_list_entry_add(&udev_device->properties, "ID_INPUT_POINTINGSTICK", "1", 0); } - if (find_bit(prop_bits, prop_cnt, INPUT_PROP_ACCELEROMETER)) { + if (test_bit(prop_bits, INPUT_PROP_ACCELEROMETER)) { udev_list_entry_add(&udev_device->properties, "ID_INPUT_ACCELEROMETER", "1", 0); } - if (find_bit(ev_bits, ev_cnt, EV_SW)) { + if (test_bit(ev_bits, EV_SW)) { udev_list_entry_add(&udev_device->properties, "ID_INPUT_SWITCH", "1", 0); } - if (find_bit(ev_bits, ev_cnt, EV_REL)) { - if (find_bit(rel_bits, rel_cnt, REL_Y) && find_bit(rel_bits, rel_cnt, REL_X) && - find_bit(key_bits, key_cnt, BTN_MOUSE)) { + if (test_bit(ev_bits, EV_REL)) { + if (test_bit(rel_bits, REL_Y) && test_bit(rel_bits, REL_X) && + test_bit(key_bits, BTN_MOUSE)) { udev_list_entry_add(&udev_device->properties, "ID_INPUT_MOUSE", "1", 0); } } - else if (find_bit(ev_bits, ev_cnt, EV_ABS)) { - if (find_bit(key_bits, key_cnt, BTN_SELECT) || find_bit(key_bits, key_cnt, BTN_TR) || - find_bit(key_bits, key_cnt, BTN_START) || find_bit(key_bits, key_cnt, BTN_TL)) { - if (find_bit(key_bits, key_cnt, BTN_TOUCH)) { + else if (test_bit(ev_bits, EV_ABS)) { + if (test_bit(key_bits, BTN_SELECT) || test_bit(key_bits, BTN_TR) || + test_bit(key_bits, BTN_START) || test_bit(key_bits, BTN_TL)) { + if (test_bit(key_bits, BTN_TOUCH)) { udev_list_entry_add(&udev_device->properties, "ID_INPUT_TOUCHSCREEN", "1", 0); } else { udev_list_entry_add(&udev_device->properties, "ID_INPUT_JOYSTICK", "1", 0); } } - else if (find_bit(abs_bits, abs_cnt, ABS_Y) && find_bit(abs_bits, abs_cnt, ABS_X)) { - if (find_bit(abs_bits, abs_cnt, ABS_Z) && !find_bit(ev_bits, ev_cnt, EV_KEY)) { + else if (test_bit(abs_bits, ABS_Y) && test_bit(abs_bits, ABS_X)) { + if (test_bit(abs_bits, ABS_Z) && !test_bit(ev_bits, EV_KEY)) { udev_list_entry_add(&udev_device->properties, "ID_INPUT_ACCELEROMETER", "1", 0); } - else if (find_bit(key_bits, key_cnt, BTN_STYLUS) || find_bit(key_bits, key_cnt, BTN_TOOL_PEN)) { + else if (test_bit(key_bits, BTN_STYLUS) || test_bit(key_bits, BTN_TOOL_PEN)) { udev_list_entry_add(&udev_device->properties, "ID_INPUT_TABLET", "1", 0); } - else if (find_bit(key_bits, key_cnt, BTN_TOUCH)) { - if (find_bit(key_bits, key_cnt, BTN_TOOL_FINGER)) { + else if (test_bit(key_bits, BTN_TOUCH)) { + if (test_bit(key_bits, BTN_TOOL_FINGER)) { udev_list_entry_add(&udev_device->properties, "ID_INPUT_TOUCHPAD", "1", 0); } else { udev_list_entry_add(&udev_device->properties, "ID_INPUT_TOUCHSCREEN", "1", 0); } } - else if (find_bit(key_bits, key_cnt, BTN_MOUSE)) { + else if (test_bit(key_bits, BTN_MOUSE)) { udev_list_entry_add(&udev_device->properties, "ID_INPUT_MOUSE", "1", 0); } } } - if (find_bit(ev_bits, ev_cnt, EV_KEY)) { + if (test_bit(ev_bits, EV_KEY)) { udev_list_entry_add(&udev_device->properties, "ID_INPUT_KEY", "1", 0); - if (find_bit(key_bits, key_cnt, KEY_ENTER)) { + if (test_bit(key_bits, KEY_ENTER)) { udev_list_entry_add(&udev_device->properties, "ID_INPUT_KEYBOARD", "1", 0); } }