Hook up libevdev as backend

libevdev wraps the various peculiarities of the evdev kernel API into a
type-safe API. It also buffers the device so checking for specific features at
a later time is easier than re-issuing the ioctls. Plus, it gives us almost
free support for SYN_DROPPED events (in the following patch).

This patch switches all the bit checks over to libevdev and leaves the event
processing as-is. Makes it easier to review.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Jonas Ådahl <jadahl@gmail.com>
This commit is contained in:
Peter Hutterer 2013-12-06 12:01:47 +10:00
parent 3a07b03df5
commit f925cee8df
5 changed files with 52 additions and 83 deletions

View file

@ -44,6 +44,7 @@ AC_CHECK_DECL(CLOCK_MONOTONIC,[],
PKG_PROG_PKG_CONFIG()
PKG_CHECK_MODULES(MTDEV, [mtdev >= 1.1.0])
PKG_CHECK_MODULES(LIBUDEV, [libudev])
PKG_CHECK_MODULES(LIBEVDEV, [libevdev >= 0.4])
if test "x$GCC" = "xyes"; then
GCC_CFLAGS="-Wall -Wextra -Wno-unused-parameter -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden"
@ -64,20 +65,16 @@ AC_ARG_ENABLE(tests,
[build_tests="$enableval"],
[build_tests="auto"])
PKG_CHECK_MODULES(LIBEVDEV, [libevdev >= 0.4], [HAVE_LIBEVDEV="yes"], [HAVE_LIBEVDEV="no"])
PKG_CHECK_MODULES(CHECK, [check >= 0.9.9], [HAVE_CHECK="yes"], [HAVE_CHECK="no"])
if test "x$build_tests" = "xauto"; then
if test "x$HAVE_CHECK" = "xyes" -a "x$HAVE_LIBEVDEV" = "xyes"; then
if test "x$HAVE_CHECK" = "xyes"; then
build_tests="yes"
fi
fi
if test "x$build_tests" = "xyes" -a "x$HAVE_CHECK" = "xno"; then
AC_MSG_ERROR([Cannot build tests, check is missing])
fi
if test "x$build_tests" = "xyes" -a "x$HAVE_LIBEVDEV" = "xno"; then
AC_MSG_ERROR([Cannot build tests, libevdev is missing])
fi
AM_CONDITIONAL(BUILD_TESTS, [test "x$build_tests" = "xyes"])

View file

@ -20,9 +20,11 @@ libinput_la_SOURCES = \
libinput_la_LIBADD = $(MTDEV_LIBS) \
$(LIBUDEV_LIBS) \
$(LIBEVDEV_LIBS) \
-lm
libinput_la_CFLAGS = $(MTDEV_CFLAGS) \
$(LIBUDEV_CFLAGS) \
$(LIBEVDEV_CFLAGS) \
$(GCC_CFLAGS)
pkgconfigdir = $(libdir)/pkgconfig

View file

@ -170,16 +170,16 @@ struct touchpad_dispatch {
static enum touchpad_model
get_touchpad_model(struct evdev_device *device)
{
struct input_id id;
int vendor, product;
unsigned int i;
if (ioctl(device->fd, EVIOCGID, &id) < 0)
return TOUCHPAD_MODEL_UNKNOWN;
vendor = libevdev_get_id_vendor(device->evdev);
product = libevdev_get_id_product(device->evdev);
for (i = 0; i < ARRAY_LENGTH(touchpad_spec_table); i++)
if (touchpad_spec_table[i].vendor == id.vendor &&
if (touchpad_spec_table[i].vendor == vendor &&
(!touchpad_spec_table[i].product ||
touchpad_spec_table[i].product == id.product))
touchpad_spec_table[i].product == product))
return touchpad_spec_table[i].model;
return TOUCHPAD_MODEL_UNKNOWN;
@ -730,9 +730,7 @@ touchpad_init(struct touchpad_dispatch *touchpad,
{
struct motion_filter *accel;
unsigned long prop_bits[INPUT_PROP_MAX];
struct input_absinfo absinfo;
unsigned long abs_bits[NBITS(ABS_MAX)];
const struct input_absinfo *absinfo;
bool has_buttonpad;
@ -746,16 +744,13 @@ touchpad_init(struct touchpad_dispatch *touchpad,
/* Detect model */
touchpad->model = get_touchpad_model(device);
ioctl(device->fd, EVIOCGPROP(sizeof(prop_bits)), prop_bits);
has_buttonpad = TEST_BIT(prop_bits, INPUT_PROP_BUTTONPAD);
has_buttonpad = libevdev_has_property(device->evdev, INPUT_PROP_BUTTONPAD);
/* Configure pressure */
ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits);
if (TEST_BIT(abs_bits, ABS_PRESSURE)) {
ioctl(device->fd, EVIOCGABS(ABS_PRESSURE), &absinfo);
if ((absinfo = libevdev_get_abs_info(device->evdev, ABS_PRESSURE))) {
configure_touchpad_pressure(touchpad,
absinfo.minimum,
absinfo.maximum);
absinfo->minimum,
absinfo->maximum);
}
/* Configure acceleration factor */

View file

@ -493,11 +493,7 @@ evdev_device_dispatch(void *data)
static int
evdev_configure_device(struct evdev_device *device)
{
struct input_absinfo absinfo;
unsigned long ev_bits[NBITS(EV_MAX)];
unsigned long abs_bits[NBITS(ABS_MAX)];
unsigned long rel_bits[NBITS(REL_MAX)];
unsigned long key_bits[NBITS(KEY_MAX)];
const struct input_absinfo *absinfo;
int has_abs, has_rel, has_mt;
int has_button, has_keyboard, has_touch;
unsigned int i;
@ -509,84 +505,71 @@ evdev_configure_device(struct evdev_device *device)
has_keyboard = 0;
has_touch = 0;
ioctl(device->fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits);
if (TEST_BIT(ev_bits, EV_ABS)) {
ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)),
abs_bits);
if (libevdev_has_event_type(device->evdev, EV_ABS)) {
if (TEST_BIT(abs_bits, ABS_X)) {
ioctl(device->fd, EVIOCGABS(ABS_X), &absinfo);
device->abs.min_x = absinfo.minimum;
device->abs.max_x = absinfo.maximum;
if ((absinfo = libevdev_get_abs_info(device->evdev, ABS_X))) {
device->abs.min_x = absinfo->minimum;
device->abs.max_x = absinfo->maximum;
has_abs = 1;
}
if (TEST_BIT(abs_bits, ABS_Y)) {
ioctl(device->fd, EVIOCGABS(ABS_Y), &absinfo);
device->abs.min_y = absinfo.minimum;
device->abs.max_y = absinfo.maximum;
if ((absinfo = libevdev_get_abs_info(device->evdev, ABS_Y))) {
device->abs.min_y = absinfo->minimum;
device->abs.max_y = absinfo->maximum;
has_abs = 1;
}
/* We only handle the slotted Protocol B in weston.
Devices with ABS_MT_POSITION_* but not ABS_MT_SLOT
require mtdev for conversion. */
if (TEST_BIT(abs_bits, ABS_MT_POSITION_X) &&
TEST_BIT(abs_bits, ABS_MT_POSITION_Y)) {
ioctl(device->fd, EVIOCGABS(ABS_MT_POSITION_X),
&absinfo);
device->abs.min_x = absinfo.minimum;
device->abs.max_x = absinfo.maximum;
ioctl(device->fd, EVIOCGABS(ABS_MT_POSITION_Y),
&absinfo);
device->abs.min_y = absinfo.minimum;
device->abs.max_y = absinfo.maximum;
if (libevdev_has_event_code(device->evdev, EV_ABS, ABS_MT_POSITION_X) &&
libevdev_has_event_code(device->evdev, EV_ABS, ABS_MT_POSITION_Y)) {
absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_POSITION_X);
device->abs.min_x = absinfo->minimum;
device->abs.max_x = absinfo->maximum;
absinfo = libevdev_get_abs_info(device->evdev, ABS_MT_POSITION_Y);
device->abs.min_y = absinfo->minimum;
device->abs.max_y = absinfo->maximum;
device->is_mt = 1;
has_touch = 1;
has_mt = 1;
if (!TEST_BIT(abs_bits, ABS_MT_SLOT)) {
if (!libevdev_has_event_code(device->evdev, EV_ABS, ABS_MT_SLOT)) {
device->mtdev = mtdev_new_open(device->fd);
if (!device->mtdev)
return -1;
device->mt.slot = device->mtdev->caps.slot.value;
} else {
ioctl(device->fd, EVIOCGABS(ABS_MT_SLOT),
&absinfo);
device->mt.slot = absinfo.value;
device->mt.slot = libevdev_get_current_slot(device->evdev);
}
}
}
if (TEST_BIT(ev_bits, EV_REL)) {
ioctl(device->fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)),
rel_bits);
if (TEST_BIT(rel_bits, REL_X) || TEST_BIT(rel_bits, REL_Y))
if (libevdev_has_event_code(device->evdev, EV_REL, REL_X) ||
libevdev_has_event_code(device->evdev, EV_REL, REL_Y))
has_rel = 1;
}
if (TEST_BIT(ev_bits, EV_KEY)) {
ioctl(device->fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)),
key_bits);
if (TEST_BIT(key_bits, BTN_TOOL_FINGER) &&
!TEST_BIT(key_bits, BTN_TOOL_PEN) &&
if (libevdev_has_event_type(device->evdev, EV_KEY)) {
if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_TOOL_FINGER) &&
!libevdev_has_event_code(device->evdev, EV_KEY, BTN_TOOL_PEN) &&
(has_abs || has_mt)) {
device->dispatch = evdev_touchpad_create(device);
}
for (i = KEY_ESC; i < KEY_MAX; i++) {
if (i >= BTN_MISC && i < KEY_OK)
continue;
if (TEST_BIT(key_bits, i)) {
if (libevdev_has_event_code(device->evdev, EV_KEY, i)) {
has_keyboard = 1;
break;
}
}
if (TEST_BIT(key_bits, BTN_TOUCH))
if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_TOUCH))
has_touch = 1;
for (i = BTN_MISC; i < BTN_JOYSTICK; i++) {
if (TEST_BIT(key_bits, i)) {
if (libevdev_has_event_code(device->evdev, EV_KEY, i)) {
has_button = 1;
break;
}
}
}
if (TEST_BIT(ev_bits, EV_LED))
if (libevdev_has_event_type(device->evdev, EV_LED))
has_keyboard = 1;
if ((has_abs || has_rel) && has_button)
@ -606,7 +589,7 @@ evdev_device_create(struct libinput_seat *seat,
{
struct libinput *libinput = seat->libinput;
struct evdev_device *device;
char devname[256] = "unknown";
int rc;
int fd;
int unhandled_device = 0;
@ -626,6 +609,10 @@ evdev_device_create(struct libinput_seat *seat,
libinput_device_init(&device->base, seat);
rc = libevdev_new_from_fd(fd, &device->evdev);
if (rc != 0)
return NULL;
device->seat_caps = 0;
device->is_mt = 0;
device->mtdev = NULL;
@ -637,10 +624,7 @@ evdev_device_create(struct libinput_seat *seat,
device->dispatch = NULL;
device->fd = fd;
device->pending_event = EVDEV_NONE;
ioctl(device->fd, EVIOCGNAME(sizeof(devname)), devname);
devname[sizeof(devname) - 1] = '\0';
device->devname = strdup(devname);
device->devname = libevdev_get_name(device->evdev);
libinput_seat_ref(seat);
@ -744,8 +728,7 @@ evdev_device_destroy(struct evdev_device *device)
dispatch->interface->destroy(dispatch);
libinput_seat_unref(device->base.seat);
free(device->devname);
libevdev_free(device->evdev);
free(device->devnode);
free(device->sysname);
free(device);

View file

@ -27,6 +27,7 @@
#include "config.h"
#include <linux/input.h>
#include <libevdev/libevdev.h>
#include "libinput-private.h"
@ -55,10 +56,11 @@ struct evdev_device {
struct libinput_source *source;
struct evdev_dispatch *dispatch;
struct libevdev *evdev;
char *output_name;
char *devnode;
char *sysname;
char *devname;
const char *devname;
int fd;
struct {
int min_x, max_x, min_y, max_y;
@ -86,16 +88,6 @@ struct evdev_device {
int is_mt;
};
/* copied from udev/extras/input_id/input_id.c */
/* we must use this kernel-compatible implementation */
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
#define OFF(x) ((x)%BITS_PER_LONG)
#define BIT(x) (1UL<<OFF(x))
#define LONG(x) ((x)/BITS_PER_LONG)
#define TEST_BIT(array, bit) ((array[LONG(bit)] >> OFF(bit)) & 1)
/* end copied */
#define EVDEV_UNHANDLED_DEVICE ((struct evdev_device *) 1)
struct evdev_dispatch;