[PATCH evemu 3/7] Switch to using a libevdev backend
Peter Hutterer
peter.hutterer at who-t.net
Thu Nov 21 16:19:58 PST 2013
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
configure.ac | 2 +
evemu.pc.in | 1 +
src/Makefile.am | 4 +
src/evemu-impl.h | 15 +-
src/evemu.c | 431 ++++++++++++++++++-------------------------------------
5 files changed, 153 insertions(+), 300 deletions(-)
diff --git a/configure.ac b/configure.ac
index 577401f..75f5ad1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -33,6 +33,8 @@ AC_PROG_CXX
AC_PROG_INSTALL
AM_PATH_PYTHON([2.6])
+PKG_CHECK_MODULES([LIBEVDEV], [libevdev >= 0.4])
+
# man page generation
AC_ARG_VAR([XMLTO], [Path to xmlto command])
AC_PATH_PROG([XMLTO], [xmlto])
diff --git a/evemu.pc.in b/evemu.pc.in
index 1ab741e..e895e8b 100644
--- a/evemu.pc.in
+++ b/evemu.pc.in
@@ -6,5 +6,6 @@ includedir=@includedir@
Name: evemu
Description: Kernel device emulation
Version: @PACKAGE_VERSION@
+Requires.private: libevdev
Libs: -L${libdir} -levemu
Cflags: -I${includedir}
diff --git a/src/Makefile.am b/src/Makefile.am
index a90b431..f8ddb80 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -16,6 +16,10 @@ libevemu_la_SOURCES = \
evemu.h \
version.h
+libevemu_la_LIBADD = $(LIBEVDEV_LIBS)
+
+AM_CPPFLAGS = -I$(top_srcdir)/include/ $(LIBEVDEV_CFLAGS)
+
libevemuincludedir = $(includedir)
libevemuinclude_HEADERS = evemu.h
diff --git a/src/evemu-impl.h b/src/evemu-impl.h
index 9844c60..1f2aacb 100644
--- a/src/evemu-impl.h
+++ b/src/evemu-impl.h
@@ -19,18 +19,17 @@
#include <evemu.h>
#include <linux/uinput.h>
-
-#define EVPLAY_NBITS KEY_CNT
-#define EVPLAY_NBYTES ((EVPLAY_NBITS + 7) / 8)
+#include <libevdev/libevdev.h>
+#include <libevdev/libevdev-uinput.h>
struct evemu_device {
unsigned int version;
- char name[UINPUT_MAX_NAME_SIZE];
- struct input_id id;
- unsigned char prop[EVPLAY_NBYTES];
- unsigned char mask[EV_CNT][EVPLAY_NBYTES];
+ struct libevdev *evdev;
+ struct libevdev_uinput *uidev;
+ /* we read in properties and bits 8 at a time, but the file format
+ * has no hint which byte we're up to. So we count what we've read
+ * already to know where the next one tacks onto */
int pbytes, mbytes[EV_CNT];
- struct input_absinfo abs[ABS_CNT];
};
#endif
diff --git a/src/evemu.c b/src/evemu.c
index 67b7645..39d66f9 100644
--- a/src/evemu.c
+++ b/src/evemu.c
@@ -54,18 +54,12 @@
#include <unistd.h>
#include "version.h"
-#include "event-names.h"
/* File format version we write out
NOTE: if you bump the version number, make sure you update README */
#define EVEMU_FILE_MAJOR 1
#define EVEMU_FILE_MINOR 2
-#ifndef UI_SET_PROPBIT
-#define UI_SET_PROPBIT _IOW(UINPUT_IOCTL_BASE, 110, int)
-#define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len)
-#endif
-
#define SYSCALL(call) while (((call) == -1) && (errno == EINTR))
enum error_level {
@@ -120,20 +114,17 @@ static int next_line(FILE *fp, char **line, size_t *sz)
return 0;
}
-static void copy_bits(unsigned char *mask, const unsigned long *bits, int bytes)
-{
- int i;
- for (i = 0; i < bytes; i++) {
- int pos = 8 * (i % sizeof(long));
- mask[i] = (bits[i / sizeof(long)] >> pos) & 0xff;
- }
-}
struct evemu_device *evemu_new(const char *name)
{
struct evemu_device *dev = calloc(1, sizeof(struct evemu_device));
if (dev) {
+ dev->evdev = libevdev_new();
+ if (!dev->evdev) {
+ free(dev);
+ return NULL;
+ }
dev->version = EVEMU_VERSION;
evemu_set_name(dev, name);
}
@@ -143,6 +134,9 @@ struct evemu_device *evemu_new(const char *name)
void evemu_delete(struct evemu_device *dev)
{
+ if (dev->uidev)
+ evemu_destroy(dev, libevdev_uinput_get_fd(dev->uidev));
+ libevdev_free(dev->evdev);
free(dev);
}
@@ -153,186 +147,148 @@ unsigned int evemu_get_version(const struct evemu_device *dev)
const char *evemu_get_name(const struct evemu_device *dev)
{
- return dev->name;
+ return libevdev_get_name(dev->evdev);
}
void evemu_set_name(struct evemu_device *dev, const char *name)
{
- if (name && strlen(name) < sizeof(dev->name))
- strcpy(dev->name, name);
+ if (name)
+ libevdev_set_name(dev->evdev, name);
}
-unsigned int evemu_get_id_bustype(const struct evemu_device *dev)
-{
- return dev->id.bustype;
+#define ID_GETTER(field) \
+unsigned int evemu_get_id_##field(const struct evemu_device *dev) { \
+ return libevdev_get_id_##field(dev->evdev); \
}
-void evemu_set_id_bustype(struct evemu_device *dev,
- unsigned int bustype)
-{
- dev->id.bustype = bustype;
-}
-
-unsigned int evemu_get_id_vendor(const struct evemu_device *dev)
-{
- return dev->id.vendor;
-}
-
-void evemu_set_id_vendor(struct evemu_device *dev,
- unsigned int vendor)
-{
- dev->id.vendor = vendor;
-}
+ID_GETTER(bustype)
+ID_GETTER(version)
+ID_GETTER(product)
+ID_GETTER(vendor)
-unsigned int evemu_get_id_product(const struct evemu_device *dev)
-{
- return dev->id.product;
+#define ID_SETTER(field) \
+void evemu_set_id_##field(struct evemu_device *dev, unsigned int value) { \
+ libevdev_set_id_##field(dev->evdev, value); \
}
-void evemu_set_id_product(struct evemu_device *dev,
- unsigned int product)
-{
- dev->id.product = product;
-}
+ID_SETTER(bustype)
+ID_SETTER(version)
+ID_SETTER(product)
+ID_SETTER(vendor)
-unsigned int evemu_get_id_version(const struct evemu_device *dev)
-{
- return dev->id.version;
+#define ABS_GETTER(field) \
+int evemu_get_abs_##field(const struct evemu_device *dev, int code) { \
+ return libevdev_get_abs_##field(dev->evdev, code); \
}
-void evemu_set_id_version(struct evemu_device *dev,
- unsigned int version)
-{
- dev->id.version = version;
-}
+ABS_GETTER(minimum)
+ABS_GETTER(maximum)
+ABS_GETTER(fuzz)
+ABS_GETTER(flat)
+ABS_GETTER(resolution)
-int evemu_get_abs_minimum(const struct evemu_device *dev, int code)
-{
- return dev->abs[code].minimum;
+#define ABS_SETTER(field) \
+void evemu_set_abs_##field(struct evemu_device *dev, int code, int value) { \
+ libevdev_set_abs_##field(dev->evdev, code, value); \
}
-void evemu_set_abs_minimum(struct evemu_device *dev, int code, int min)
-{
- dev->abs[code].minimum = min;
-}
-
-int evemu_get_abs_maximum(const struct evemu_device *dev, int code)
-{
- return dev->abs[code].maximum;
-}
+ABS_SETTER(minimum)
+ABS_SETTER(maximum)
+ABS_SETTER(fuzz)
+ABS_SETTER(flat)
+ABS_SETTER(resolution)
int evemu_get_abs_current_value(const struct evemu_device *dev, int code)
{
- return dev->abs[code].value;
-}
-
-void evemu_set_abs_maximum(struct evemu_device *dev, int code, int max)
-{
- dev->abs[code].maximum = max;
-}
-
-int evemu_get_abs_fuzz(const struct evemu_device *dev, int code)
-{
- return dev->abs[code].fuzz;
-}
-
-void evemu_set_abs_fuzz(struct evemu_device *dev, int code, int fuzz)
-{
- dev->abs[code].fuzz = fuzz;
-}
-
-int evemu_get_abs_flat(const struct evemu_device *dev, int code)
-{
- return dev->abs[code].flat;
-}
-
-void evemu_set_abs_flat(struct evemu_device *dev, int code, int flat)
-{
- dev->abs[code].flat = flat;
-}
-
-int evemu_get_abs_resolution(const struct evemu_device *dev, int code)
-{
- return dev->abs[code].resolution;
-}
-
-void evemu_set_abs_resolution(struct evemu_device *dev, int code, int res)
-{
- dev->abs[code].resolution = res;
+ return libevdev_get_event_value(dev->evdev, EV_ABS, code);
}
int evemu_has_prop(const struct evemu_device *dev, int code)
{
- return (dev->prop[code >> 3] >> (code & 7)) & 1;
+ return libevdev_has_property(dev->evdev, code);
}
int evemu_has_event(const struct evemu_device *dev, int type, int code)
{
- return (dev->mask[type][code >> 3] >> (code & 7)) & 1;
+ return libevdev_has_event_code(dev->evdev, type, code);
}
int evemu_has_bit(const struct evemu_device *dev, int type)
{
- return (dev->mask[0][type >> 3] >> (type & 7)) & 1;
+ return libevdev_has_event_type(dev->evdev, type);
}
int evemu_extract(struct evemu_device *dev, int fd)
{
- unsigned long bits[64];
- int rc, i;
-
- memset(dev, 0, sizeof(*dev));
-
- SYSCALL(rc = ioctl(fd, EVIOCGNAME(sizeof(dev->name)-1), dev->name));
- if (rc < 0)
- return rc;
-
- SYSCALL(rc = ioctl(fd, EVIOCGID, &dev->id));
- if (rc < 0)
- return rc;
-
- SYSCALL(rc = ioctl(fd, EVIOCGPROP(sizeof(bits)), bits));
- if (rc >= 0) {
- copy_bits(dev->prop, bits, rc);
- dev->pbytes = rc;
- }
-
- for (i = 0; i < EV_CNT; i++) {
- SYSCALL(rc = ioctl(fd, EVIOCGBIT(i, sizeof(bits)), bits));
- if (rc < 0)
- continue;
- copy_bits(dev->mask[i], bits, rc);
- dev->mbytes[i] = rc;
+ if (libevdev_get_fd(dev->evdev) != -1) {
+ libevdev_free(dev->evdev);
+ dev->evdev = libevdev_new();
+ if (!dev->evdev)
+ return -ENOMEM;
}
+ return libevdev_set_fd(dev->evdev, fd);
+}
- for (i = 0; i < ABS_CNT; i++) {
- if (!evemu_has_event(dev, EV_ABS, i))
- continue;
- SYSCALL(rc = ioctl(fd, EVIOCGABS(i), &dev->abs[i]));
- if (rc < 0)
- return rc;
- }
+static inline int bit_is_set(unsigned char *mask, int bit)
+{
+ return !!(mask[bit/8] & (1 << (bit & 0x7)));
+}
- return 0;
+static inline void set_bit(unsigned char *mask, int bit)
+{
+ mask[bit/8] |= 1 << (bit & 0x7);
}
-static void write_prop(FILE * fp, const unsigned char *mask, int bytes)
+#define max(a, b) (a > b) ? a : b
+
+static void write_prop(FILE * fp, const struct evemu_device *dev)
{
+#ifdef INPUT_PROP_MAX
int i;
- for (i = 0; i < bytes; i += 8)
+ unsigned char mask[max(8, (INPUT_PROP_MAX + 7)/8)] = {0};
+
+ for (i = 0; i < INPUT_PROP_MAX; i ++) {
+ if (evemu_has_prop(dev, i)) {
+ printf("prop bit set for %d\n", i);
+ set_bit(mask, i);
+ }
+ }
+
+ for (i = 0; i < (INPUT_PROP_MAX + 7)/8; i +=8) {
fprintf(fp, "P: %02x %02x %02x %02x %02x %02x %02x %02x\n",
mask[i], mask[i + 1], mask[i + 2], mask[i + 3],
mask[i + 4], mask[i + 5], mask[i + 6], mask[i + 7]);
+ }
+#endif
}
-static void write_mask(FILE * fp, int index,
- const unsigned char *mask, int bytes)
+static void write_mask(FILE * fp, const struct evemu_device *dev)
{
- int i;
- for (i = 0; i < bytes; i += 8)
- fprintf(fp, "B: %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- index, mask[i], mask[i + 1], mask[i + 2], mask[i + 3],
- mask[i + 4], mask[i + 5], mask[i + 6], mask[i + 7]);
+ unsigned int type;
+
+ /* Write EV_SYN/SYN_REPORT only. Just because older versions
+ printed out exactly that */
+ fprintf(fp, "B: 00 0b 00 00 00 00 00 00 00\n");
+
+ for (type = 1 /* don't write EV_SYN */; type < EV_CNT; type++) {
+ int i;
+ int max = libevdev_event_type_get_max(type);
+ unsigned char mask[KEY_CNT] = {0};
+ unsigned int code;
+
+ if (max == -1)
+ continue;
+
+ for (code = 0; code < max; code++)
+ if (evemu_has_event(dev, type, code))
+ set_bit(mask, code);
+
+ for (i = 0; i < (max + 7)/8; i += 8) {
+ fprintf(fp, "B: %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ type, mask[i], mask[i + 1], mask[i + 2], mask[i + 3],
+ mask[i + 4], mask[i + 5], mask[i + 6], mask[i + 7]);
+ }
+ }
}
static void write_abs(FILE *fp, int index, const struct input_absinfo *abs)
@@ -354,13 +310,13 @@ static void write_desc(const struct evemu_device *dev, FILE *fp)
if (!evemu_has_bit(dev, i))
continue;
- fprintf(fp, "# Event type %d (%s)\n", i, event_get_type_name(i));
- for (j = 0; j < KEY_MAX; j++) {
+ fprintf(fp, "# Event type %d (%s)\n", i, libevdev_event_type_get_name(i));
+ for (j = 0; j < libevdev_event_type_get_max(i); j++) {
if (!evemu_has_event(dev, i, j))
continue;
fprintf(fp, "# Event code %d (%s)\n",
- j, event_get_code_name(i, j));
+ j, libevdev_event_code_get_name(i, j));
if (i == EV_ABS) {
fprintf(fp, "# Value %6d\n"
"# Min %6d\n"
@@ -383,7 +339,8 @@ static void write_desc(const struct evemu_device *dev, FILE *fp)
for (i = 0; i < INPUT_PROP_MAX; i++) {
if (!evemu_has_prop(dev, i))
continue;
- fprintf(fp, "# Property type %d (%s)\n", i, input_prop_map[i]);
+ fprintf(fp, "# Property type %d (%s)\n", i,
+ libevdev_property_get_name(i));
}
#endif
}
@@ -404,14 +361,12 @@ int evemu_write(const struct evemu_device *dev, FILE *fp)
evemu_get_id_product(dev),
evemu_get_id_version(dev));
- write_prop(fp, dev->prop, dev->pbytes);
-
- for (i = 0; i < EV_CNT; i++)
- write_mask(fp, i, dev->mask[i], dev->mbytes[i]);
+ write_prop(fp, dev);
+ write_mask(fp, dev);
for (i = 0; i < ABS_CNT; i++)
if (evemu_has_event(dev, EV_ABS, i))
- write_abs(fp, i, &dev->abs[i]);
+ write_abs(fp, i, libevdev_get_abs_info(dev->evdev, i));
return 0;
}
@@ -457,7 +412,7 @@ static int parse_bus_vid_pid_ver(struct evemu_device *dev, const char *line, str
static int parse_prop(struct evemu_device *dev, const char *line, struct version *fversion)
{
int matched;
- unsigned int mask[8];
+ unsigned char mask[8];
int i;
if (strlen(line) <= 2 || strncmp(line, "P:", 2) != 0)
@@ -472,8 +427,12 @@ static int parse_prop(struct evemu_device *dev, const char *line, struct version
return -1;
}
- for (i = 0; i < 8; i++)
- dev->prop[dev->pbytes++] = mask[i];
+ for (i = 0; i < sizeof(mask) * 8; i++) {
+ if (bit_is_set(mask, i))
+ libevdev_enable_property(dev->evdev, dev->pbytes * 8 + i);
+ }
+
+ dev->pbytes += 8;
return 1;
}
@@ -481,7 +440,7 @@ static int parse_prop(struct evemu_device *dev, const char *line, struct version
static int parse_mask(struct evemu_device *dev, const char *line, struct version *fversion)
{
int matched;
- unsigned int mask[8];
+ unsigned char mask[8];
unsigned int index, i;
if (strlen(line) <= 2 || strncmp(line, "B:", 2) != 0)
@@ -496,8 +455,15 @@ static int parse_mask(struct evemu_device *dev, const char *line, struct version
return -1;
}
- for (i = 0; i < 8; i++)
- dev->mask[index][dev->mbytes[index]++] = mask[i];
+ for (i = 0; i < sizeof(mask) * 8; i++) {
+ const struct input_absinfo abs = {0, 0, 1}; /* dummy */
+ if (bit_is_set(mask, i)) {
+ unsigned int code = dev->mbytes[index] * 8 + i;
+ libevdev_enable_event_code(dev->evdev, index, code, (index == EV_ABS) ? &abs : NULL);
+ }
+ }
+
+ dev->mbytes[index] += 8;
return 1;
}
@@ -560,16 +526,10 @@ int evemu_read(struct evemu_device *dev, FILE *fp)
struct version file_version; /* file format version */
size_t size = 0;
char *line = NULL;
- char *name = NULL;
- if (strlen(evemu_get_name(dev)) > 0)
- name = strdup(evemu_get_name(dev));
- memset(dev, 0, sizeof(*dev));
+ memset(dev->mbytes, 0, sizeof(*dev->mbytes));
+ dev->pbytes = 0;
dev->version = EVEMU_VERSION;
- if (name) {
- evemu_set_name(dev, name);
- free(name);
- }
/* first line _may_ be version */
if (!first_line(fp, &line, &size)) {
@@ -629,16 +589,16 @@ static void write_event_desc(FILE *fp, const struct input_event *ev)
if (ev->type == EV_SYN) {
if (ev->code == SYN_MT_REPORT)
fprintf(fp, "# ++++++++++++ %s (%d) ++++++++++\n",
- event_get_code_name(ev->type, ev->code),
+ libevdev_event_code_get_name(ev->type, ev->code),
ev->value);
else
fprintf(fp, "# ------------ %s (%d) ----------\n",
- event_get_code_name(ev->type, ev->code),
+ libevdev_event_code_get_name(ev->type, ev->code),
ev->value);
} else {
fprintf(fp, "# %s / %-20s %d\n",
- event_get_type_name(ev->type),
- event_get_code_name(ev->type, ev->code),
+ libevdev_event_type_get_name(ev->type),
+ libevdev_event_code_get_name(ev->type, ev->code),
ev->value);
}
}
@@ -775,8 +735,8 @@ static void evemu_warn_about_incompatible_event(struct input_event *ev)
error(WARNING, "You are trying to play events incompatbile with this device. "
"Is this the right device/recordings file?\n");
error(WARNING, "%s %s is not supported by this device.\n",
- event_get_type_name(ev->type),
- event_get_code_name(ev->type, ev->code));
+ libevdev_event_type_get_name(ev->type),
+ libevdev_event_code_get_name(ev->type, ev->code));
} else if (warned == max_warnings + 1) {
error(INFO, "warned about incompatible events %d times. Will be quiet now.\n",
warned - 1);
@@ -812,128 +772,15 @@ int evemu_play(FILE *fp, int fd)
return 0;
}
-static int set_prop_bit(int fd, int code)
-{
- int ret;
- SYSCALL(ret = ioctl(fd, UI_SET_PROPBIT, code));
- return ret;
-}
-
-static int set_event_bit(int fd, int type, int code)
-{
- int ret = 0;
-
- switch(type) {
- case EV_SYN:
- SYSCALL(ret = ioctl(fd, UI_SET_EVBIT, code));
- break;
- case EV_KEY:
- SYSCALL(ret = ioctl(fd, UI_SET_KEYBIT, code));
- break;
- case EV_REL:
- SYSCALL(ret = ioctl(fd, UI_SET_RELBIT, code));
- break;
- case EV_ABS:
- SYSCALL(ret = ioctl(fd, UI_SET_ABSBIT, code));
- break;
- case EV_MSC:
- SYSCALL(ret = ioctl(fd, UI_SET_MSCBIT, code));
- break;
- case EV_LED:
- SYSCALL(ret = ioctl(fd, UI_SET_LEDBIT, code));
- break;
- case EV_SND:
- SYSCALL(ret = ioctl(fd, UI_SET_SNDBIT, code));
- break;
- case EV_FF:
- SYSCALL(ret = ioctl(fd, UI_SET_FFBIT, code));
- break;
- case EV_SW:
- SYSCALL(ret = ioctl(fd, UI_SET_SWBIT, code));
- break;
- }
-
- return ret;
-}
-
-static int set_prop(const struct evemu_device *dev, int fd)
-{
- int bits = 8 * dev->pbytes;
- int ret, i;
- int success = 0;
- for (i = 0; i < bits; i++) {
- if (!evemu_has_prop(dev, i))
- continue;
- ret = set_prop_bit(fd, i);
- /* Older kernels aways return errors on UI_SET_PROPBIT.
- Assume that if we only get failures, it may be an older
- kernel and report success anyway. */
- if (ret < 0) {
- if (success)
- return ret;
- } else if (!success)
- success = 1;
- }
- return 0;
-}
-
-static int set_mask(const struct evemu_device *dev, int type, int fd)
-{
- int bits = 8 * dev->mbytes[type];
- int ret, i;
- for (i = 0; i < bits; i++) {
- if (!evemu_has_event(dev, type, i))
- continue;
-
- /* kernel doesn't like those */
- if (type == EV_ABS &&
- evemu_get_abs_maximum(dev, i) == 0 && evemu_get_abs_minimum(dev, i) == 0)
- continue;
-
- ret = set_event_bit(fd, type, i);
- if (ret < 0)
- return ret;
- }
- return 0;
-}
-
int evemu_create(struct evemu_device *dev, int fd)
{
- struct uinput_user_dev udev;
- int ret, i;
-
- memset(&udev, 0, sizeof(udev));
- memcpy(udev.name, dev->name, sizeof(udev.name));
- udev.id = dev->id;
- for (i = 0; i < ABS_CNT; i++) {
- if (!evemu_has_event(dev, EV_ABS, i))
- continue;
- udev.absmax[i] = evemu_get_abs_maximum(dev, i);
- udev.absmin[i] = evemu_get_abs_minimum(dev, i);
- udev.absfuzz[i] = evemu_get_abs_fuzz(dev, i);
- udev.absflat[i] = evemu_get_abs_flat(dev, i);
- }
-
- ret = set_prop(dev, fd);
- if (ret < 0)
- return ret;
-
- for (i = 0; i < EV_CNT; i++) {
- ret = set_mask(dev, i, fd);
- if (ret < 0)
- return ret;
- }
-
- SYSCALL(ret = write(fd, &udev, sizeof(udev)));
- if (ret < 0)
- return ret;
-
- SYSCALL(ret = ioctl(fd, UI_DEV_CREATE, NULL));
- return ret;
+ return libevdev_uinput_create_from_device(dev->evdev, fd, &dev->uidev);
}
void evemu_destroy(struct evemu_device *dev, int fd)
{
- int ret;
- SYSCALL(ret = ioctl(fd, UI_DEV_DESTROY, NULL));
+ if (dev->uidev) {
+ libevdev_uinput_destroy(dev->uidev);
+ dev->uidev = NULL;
+ }
}
--
1.8.3.1
More information about the Input-tools
mailing list