Update input event structures read from the kernel to match the 1.2 version of the driver.
Update the UAPI version of the header file input.h to use __inline__ instead of inline to maintain compatibility with the pedantic gcc flag used to test the headers.
There are no changes to the exposed interfaces of libevdev.
The associated kernel driver change is at https://lkml.org/lkml/2016/10/17/1146 .
Signed-off-by: Deepa Dinamani deepa.kernel@gmail.com --- include/linux/input.h | 47 ++++++++++++++++++++++++++++++++++++++++++ include/linux/uinput.h | 3 +++ libevdev/libevdev-int.h | 31 +++++++++++++++++++--------- libevdev/libevdev.c | 30 ++++++++++++++++++--------- test/test-libevdev-has-event.c | 2 +- 5 files changed, 92 insertions(+), 21 deletions(-)
diff --git a/include/linux/input.h b/include/linux/input.h index fbc968f..e253679 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -20,6 +20,29 @@ * The event structure itself */
+/* The time structure for y2038 safe raw_input_event. + * The fields use unsigned types to extend times until + * year 2106 rather than 2038. + */ +struct input_timeval { + __kernel_ulong_t tv_sec; + __kernel_ulong_t tv_usec; +}; + +struct raw_input_event { + struct input_timeval time; + __u16 type; + __u16 code; + __s32 value; +}; + +#ifndef __KERNEL__ + +/* Userspace structure. + * Definition maintained here for userspace that is not yet updated to use + * struct raw_input_event. + * Not to be used anywhere within the kernel. + */ struct input_event { struct timeval time; __u16 type; @@ -27,11 +50,35 @@ struct input_event { __s32 value; };
+static __inline__ void +raw_input_to_input_event(const struct raw_input_event *raw, struct input_event *ev) +{ + ev->time.tv_sec = raw->time.tv_sec; + ev->time.tv_usec = raw->time.tv_usec; + ev->type = raw->type; + ev->code = raw->code; + ev->value = raw->value; +} + +static __inline__ void +input_to_raw_event(const struct input_event *ev, struct raw_input_event *raw) +{ + raw->time.tv_sec = ev->time.tv_sec; + raw->time.tv_usec = ev->time.tv_usec; + raw->type = ev->type; + raw->code = ev->code; + raw->value = ev->value; +} + +#endif + /* * Protocol version. */
#define EV_VERSION 0x010001 +#define EV_VERSION_1_2 0x010002 +
/* * IOCTLs (0x00 - 0x7f) diff --git a/include/linux/uinput.h b/include/linux/uinput.h index 434f02d..c7b7054 100644 --- a/include/linux/uinput.h +++ b/include/linux/uinput.h @@ -133,6 +133,9 @@ struct uinput_abs_setup { */ #define UI_ABS_SETUP _IOW(UINPUT_IOCTL_BASE, 4, struct uinput_abs_setup)
+/* Set clockid to be used for timestamps */ +#define UI_SET_CLOCKID _IOW(UINPUT_IOCTL_BASE, 5, int) + #define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int) #define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int) #define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int) diff --git a/libevdev/libevdev-int.h b/libevdev/libevdev-int.h index e1c7ec5..8539987 100644 --- a/libevdev/libevdev-int.h +++ b/libevdev/libevdev-int.h @@ -105,7 +105,7 @@ struct libevdev { enum SyncState sync_state; enum libevdev_grab_mode grabbed;
- struct input_event *queue; + struct raw_input_event *queue; size_t queue_size; /**< size of queue in elements */ size_t queue_next; /**< next event index */ size_t queue_nsync; /**< number of sync events */ @@ -147,7 +147,7 @@ _libevdev_log_priority(const struct libevdev *dev); * @return a pointer to the next element in the queue, or NULL if the queue * is full. */ -static inline struct input_event* +static inline struct raw_input_event* queue_push(struct libevdev *dev) { if (dev->queue_next >= dev->queue_size) @@ -167,8 +167,8 @@ queue_pop(struct libevdev *dev, struct input_event *ev) if (dev->queue_next == 0) return 1;
- *ev = dev->queue[--dev->queue_next]; - + raw_input_to_input_event(&dev->queue[dev->queue_next-1], ev); + --dev->queue_next; return 0; }
@@ -177,7 +177,8 @@ queue_peek(struct libevdev *dev, size_t idx, struct input_event *ev) { if (dev->queue_next == 0 || idx > dev->queue_next) return 1; - *ev = dev->queue[idx]; + raw_input_to_input_event(&dev->queue[idx], ev); + return 0; }
@@ -192,7 +193,9 @@ queue_peek(struct libevdev *dev, size_t idx, struct input_event *ev) static inline int queue_shift_multiple(struct libevdev *dev, size_t n, struct input_event *ev) { - size_t remaining; + struct raw_input_event *raw_event; + struct input_event *event; + size_t i, remaining;
if (dev->queue_next == 0) return 0; @@ -201,8 +204,16 @@ queue_shift_multiple(struct libevdev *dev, size_t n, struct input_event *ev) n = min(n, remaining); remaining -= n;
- if (ev) - memcpy(ev, dev->queue, n * sizeof(*ev)); + raw_event = dev->queue; + event = ev; + + if (ev) { + for (i = 0; i < n; i++) { + raw_input_to_input_event(raw_event, event); + raw_event++; + event++; + } + }
memmove(dev->queue, &dev->queue[n], remaining * sizeof(*dev->queue));
@@ -228,7 +239,7 @@ queue_alloc(struct libevdev *dev, size_t size) if (size == 0) return -ENOMEM;
- dev->queue = calloc(size, sizeof(struct input_event)); + dev->queue = calloc(size, sizeof(struct raw_input_event)); if (!dev->queue) return -ENOMEM;
@@ -266,7 +277,7 @@ queue_num_free_elements(struct libevdev *dev) return dev->queue_size - dev->queue_next; }
-static inline struct input_event * +static inline struct raw_input_event * queue_next_element(struct libevdev *dev) { if (dev->queue_next == dev->queue_size) diff --git a/libevdev/libevdev.c b/libevdev/libevdev.c index 43a095c..adf351a 100644 --- a/libevdev/libevdev.c +++ b/libevdev/libevdev.c @@ -29,6 +29,7 @@ #include <unistd.h> #include <stdarg.h> #include <stdbool.h> +#include <time.h>
#include "libevdev.h" #include "libevdev-int.h" @@ -383,6 +384,10 @@ libevdev_set_fd(struct libevdev* dev, int fd) rc = ioctl(fd, EVIOCGVERSION, &dev->driver_version); if (rc < 0) goto out; + if (dev->driver_version < EV_VERSION_1_2) { + log_error(dev, "Library requires at least kernel driver version 2"); + goto out; + }
/* Built on a kernel with props, running against a kernel without property support. This should not be a fatal case, we'll be missing properties but other @@ -522,9 +527,10 @@ libevdev_get_fd(const struct libevdev* dev) }
static inline void -init_event(struct libevdev *dev, struct input_event *ev, int type, int code, int value) +init_event(struct libevdev *dev, struct raw_input_event *ev, int type, int code, int value) { - ev->time = dev->last_event_time; + ev->time.tv_sec = dev->last_event_time.tv_sec; + ev->time.tv_usec = dev->last_event_time.tv_usec; ev->type = type; ev->code = code; ev->value = value; @@ -546,7 +552,7 @@ sync_key_state(struct libevdev *dev) old = bit_is_set(dev->key_values, i); new = bit_is_set(keystate, i); if (old ^ new) { - struct input_event *ev = queue_push(dev); + struct raw_input_event *ev = queue_push(dev); init_event(dev, ev, EV_KEY, i, new ? 1 : 0); } } @@ -574,7 +580,7 @@ sync_sw_state(struct libevdev *dev) old = bit_is_set(dev->sw_values, i); new = bit_is_set(swstate, i); if (old ^ new) { - struct input_event *ev = queue_push(dev); + struct raw_input_event *ev = queue_push(dev); init_event(dev, ev, EV_SW, i, new ? 1 : 0); } } @@ -602,7 +608,7 @@ sync_led_state(struct libevdev *dev) old = bit_is_set(dev->led_values, i); new = bit_is_set(ledstate, i); if (old ^ new) { - struct input_event *ev = queue_push(dev); + struct raw_input_event *ev = queue_push(dev); init_event(dev, ev, EV_LED, i, new ? 1 : 0); } } @@ -633,7 +639,7 @@ sync_abs_state(struct libevdev *dev) goto out;
if (dev->abs_info[i].value != abs_info.value) { - struct input_event *ev = queue_push(dev); + struct raw_input_event *ev = queue_push(dev);
init_event(dev, ev, EV_ABS, i, abs_info.value); dev->abs_info[i].value = abs_info.value; @@ -648,7 +654,7 @@ out: static int sync_mt_state(struct libevdev *dev, int create_events) { - struct input_event *ev; + struct raw_input_event *ev; struct input_absinfo abs_info; int rc; int axis, slot; @@ -775,7 +781,7 @@ read_more_events(struct libevdev *dev) { int free_elem; int len; - struct input_event *next; + struct raw_input_event *next;
free_elem = queue_num_free_elements(dev); if (free_elem <= 0) @@ -834,7 +840,7 @@ static int sync_state(struct libevdev *dev) { int rc = 0; - struct input_event *ev; + struct raw_input_event *ev;
/* see section "Discarding events before synchronizing" in * libevdev/libevdev.h */ @@ -966,7 +972,8 @@ update_state(struct libevdev *dev, const struct input_event *e) break; }
- dev->last_event_time = e->time; + dev->last_event_time.tv_sec = e->time.tv_sec; + dev->last_event_time.tv_usec = e->time.tv_usec;
return rc; } @@ -1720,5 +1727,8 @@ libevdev_set_clock_id(struct libevdev *dev, int clockid) } else if (dev->fd < 0) return -EBADF;
+ if (clockid == CLOCK_REALTIME) + log_info(dev, "REALTIME clock support does not work beyond year 2106.\n"); + return ioctl(dev->fd, EVIOCSCLOCKID, &clockid) ? -errno : 0; } diff --git a/test/test-libevdev-has-event.c b/test/test-libevdev-has-event.c index 7703206..fee11fa 100644 --- a/test/test-libevdev-has-event.c +++ b/test/test-libevdev-has-event.c @@ -475,7 +475,7 @@ START_TEST(test_device_name) ck_assert_int_eq(libevdev_get_id_vendor(dev), ids.vendor); ck_assert_int_eq(libevdev_get_id_product(dev), ids.product); ck_assert_int_eq(libevdev_get_id_version(dev), ids.version); - ck_assert_int_eq(libevdev_get_driver_version(dev), EV_VERSION); + ck_assert_int_eq(libevdev_get_driver_version(dev), EV_VERSION_1_2);
uinput_device_free(uidev); libevdev_free(dev);