Support EV_REP values through libevdev_get_event_value
[platform/upstream/libevdev.git] / libevdev / libevdev.c
index 436f7a9..60bbbfc 100644 (file)
@@ -27,6 +27,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <stdarg.h>
+#include <stdbool.h>
 
 #include "libevdev.h"
 #include "libevdev-int.h"
@@ -49,18 +50,71 @@ init_event_queue(struct libevdev *dev)
 }
 
 static void
-_libevdev_log(struct libevdev *dev, const char *format, ...)
+libevdev_dflt_log_func(enum libevdev_log_priority priority,
+                      void *data,
+                      const char *file, int line, const char *func,
+                      const char *format, va_list args)
+{
+       const char *prefix;
+       switch(priority) {
+               case LIBEVDEV_LOG_ERROR: prefix = "libevdev error"; break;
+               case LIBEVDEV_LOG_INFO: prefix = "libevdev info"; break;
+               case LIBEVDEV_LOG_DEBUG:
+                                       prefix = "libevdev debug";
+                                       break;
+               default:
+                                       prefix = "libevdev INVALID LOG PRIORITY";
+                                       break;
+       }
+       /* default logging format:
+          libevev error in libevdev_some_func: blah blah
+          libevev info in libevdev_some_func: blah blah
+          libevev debug in file.c:123:libevdev_some_func: blah blah
+        */
+
+       fprintf(stderr, "%s in ", prefix);
+       if (priority == LIBEVDEV_LOG_DEBUG)
+               fprintf(stderr, "%s:%d:", file, line);
+       fprintf(stderr, "%s: ", func);
+       vfprintf(stderr, format, args);
+}
+
+/*
+ * Global logging settings.
+ */
+struct logdata log_data = {
+       LIBEVDEV_LOG_INFO,
+       libevdev_dflt_log_func,
+       NULL,
+};
+
+void
+log_msg(enum libevdev_log_priority priority,
+       void *data,
+       const char *file, int line, const char *func,
+       const char *format, ...)
 {
        va_list args;
 
+       if (!log_data.handler)
+               return;
+
        va_start(args, format);
-       dev->log(format, args);
+       log_data.handler(priority, data, file, line, func, format, args);
        va_end(args);
 }
 
 static void
-libevdev_noop_log_func(const char *format, va_list args)
+libevdev_reset(struct libevdev *dev)
 {
+       memset(dev, 0, sizeof(*dev));
+       dev->fd = -1;
+       dev->initialized = false;
+       dev->num_slots = -1;
+       dev->current_slot = -1;
+       dev->grabbed = LIBEVDEV_UNGRAB;
+       dev->sync_state = SYNC_NONE;
+       libevdev_enable_event_type(dev, EV_SYN);
 }
 
 LIBEVDEV_EXPORT struct libevdev*
@@ -68,15 +122,11 @@ libevdev_new(void)
 {
        struct libevdev *dev;
 
-       dev = calloc(1, sizeof(*dev));
+       dev = malloc(sizeof(*dev));
        if (!dev)
                return NULL;
-       dev->fd = -1;
-       dev->num_slots = -1;
-       dev->current_slot = -1;
-       dev->log = libevdev_noop_log_func;
-       dev->grabbed = LIBEVDEV_UNGRAB;
-       dev->sync_state = SYNC_NONE;
+
+       libevdev_reset(dev);
 
        return dev;
 }
@@ -113,19 +163,33 @@ libevdev_free(struct libevdev *dev)
 }
 
 LIBEVDEV_EXPORT void
-libevdev_set_log_handler(struct libevdev *dev, libevdev_log_func_t logfunc)
+libevdev_set_log_function(libevdev_log_func_t logfunc, void *data)
 {
-       if (dev == NULL)
-               return;
+       log_data.handler = logfunc;
+       log_data.userdata = data;
+}
 
-       dev->log = logfunc ? logfunc : libevdev_noop_log_func;
+LIBEVDEV_EXPORT void
+libevdev_set_log_priority(enum libevdev_log_priority priority)
+{
+       if (priority > LIBEVDEV_LOG_DEBUG)
+               priority = LIBEVDEV_LOG_DEBUG;
+       log_data.priority = priority;
+}
+
+LIBEVDEV_EXPORT enum libevdev_log_priority
+libevdev_get_log_priority(void)
+{
+       return log_data.priority;
 }
 
 LIBEVDEV_EXPORT int
 libevdev_change_fd(struct libevdev *dev, int fd)
 {
-       if (dev->fd == -1)
+       if (!dev->initialized) {
+               log_bug("device not initialized. call libevdev_set_fd() first\n");
                return -1;
+       }
        dev->fd = fd;
        return 0;
 }
@@ -137,9 +201,14 @@ libevdev_set_fd(struct libevdev* dev, int fd)
        int i;
        char buf[256];
 
-       if (dev->fd != -1)
+       if (dev->initialized) {
+               log_bug("device already initialized.\n");
+               return -EBADF;
+       } else if (fd < 0)
                return -EBADF;
 
+       libevdev_reset(dev);
+
        rc = ioctl(fd, EVIOCGBIT(0, sizeof(dev->bits)), dev->bits);
        if (rc < 0)
                goto out;
@@ -195,8 +264,12 @@ libevdev_set_fd(struct libevdev* dev, int fd)
        if (rc < 0)
                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
+          than that everything is as expected.
+        */
        rc = ioctl(fd, EVIOCGPROP(sizeof(dev->props)), dev->props);
-       if (rc < 0)
+       if (rc < 0 && errno != EINVAL)
                goto out;
 
        rc = ioctl(fd, EVIOCGBIT(EV_REL, sizeof(dev->rel_bits)), dev->rel_bits);
@@ -282,7 +355,10 @@ libevdev_set_fd(struct libevdev* dev, int fd)
         * Same with the valuators, really, but they may not change.
         */
 
+       dev->initialized = true;
 out:
+       if (rc)
+               libevdev_reset(dev);
        return rc ? -errno : 0;
 }
 
@@ -421,11 +497,14 @@ sync_mt_state(struct libevdev *dev, int create_events)
 {
        int rc;
        int i;
+       int ioctl_success = 0;
        struct mt_state {
                int code;
                int val[MAX_SLOTS];
        } mt_state[ABS_MT_CNT];
 
+       memset(&mt_state, 0, sizeof(mt_state));
+
        for (i = ABS_MT_MIN; i <= ABS_MT_MAX; i++) {
                int idx;
                if (i == ABS_MT_SLOT)
@@ -437,8 +516,15 @@ sync_mt_state(struct libevdev *dev, int create_events)
                idx = i - ABS_MT_MIN;
                mt_state[idx].code = i;
                rc = ioctl(dev->fd, EVIOCGMTSLOTS(sizeof(struct mt_state)), &mt_state[idx]);
-               if (rc < 0)
-                       goto out;
+               if (rc < 0) {
+                       /* if the first ioctl fails with -EINVAL, chances are the kernel
+                          doesn't support the ioctl. Simply continue */
+                       if (errno == -EINVAL && !ioctl_success) {
+                               rc = 0;
+                       } else /* if the second, ... ioctl fails, really fail */
+                               goto out;
+               } else if (ioctl_success == 0)
+                       ioctl_success = 1;
        }
 
        for (i = 0; i < dev->num_slots; i++) {
@@ -660,15 +746,20 @@ read_more_events(struct libevdev *dev)
 LIBEVDEV_EXPORT int
 libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event *ev)
 {
-       int rc = 0;
+       int rc = LIBEVDEV_READ_STATUS_SUCCESS;
 
-       if (dev->fd < 0)
-               return -ENODEV;
+       if (!dev->initialized) {
+               log_bug("device not initialized. call libevdev_set_fd() first\n");
+               return -EBADF;
+       } else if (dev->fd < 0)
+               return -EBADF;
 
-       if (!(flags & (LIBEVDEV_READ_NORMAL|LIBEVDEV_READ_SYNC|LIBEVDEV_FORCE_SYNC)))
+       if (!(flags & (LIBEVDEV_READ_FLAG_NORMAL|LIBEVDEV_READ_FLAG_SYNC|LIBEVDEV_READ_FLAG_FORCE_SYNC))) {
+               log_bug("invalid flags %#x\n.\n", flags);
                return -EINVAL;
+       }
 
-       if (flags & LIBEVDEV_READ_SYNC) {
+       if (flags & LIBEVDEV_READ_FLAG_SYNC) {
                if (dev->sync_state == SYNC_NEEDED) {
                        rc = sync_state(dev);
                        if (rc != 0)
@@ -703,16 +794,16 @@ libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event
           read in any more.
         */
        do {
-               if (!(flags & LIBEVDEV_READ_BLOCKING) ||
+               if (!(flags & LIBEVDEV_READ_FLAG_BLOCKING) ||
                    queue_num_elements(dev) == 0) {
                        rc = read_more_events(dev);
                        if (rc < 0 && rc != -EAGAIN)
                                goto out;
                }
 
-               if (flags & LIBEVDEV_FORCE_SYNC) {
+               if (flags & LIBEVDEV_READ_FLAG_FORCE_SYNC) {
                        dev->sync_state = SYNC_NEEDED;
-                       rc = 1;
+                       rc = LIBEVDEV_READ_STATUS_SYNC;
                        goto out;
                }
 
@@ -728,12 +819,12 @@ libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event
        rc = 0;
        if (ev->type == EV_SYN && ev->code == SYN_DROPPED) {
                dev->sync_state = SYNC_NEEDED;
-               rc = 1;
+               rc = LIBEVDEV_READ_STATUS_SYNC;
        }
 
-       if (flags & LIBEVDEV_READ_SYNC && dev->queue_nsync > 0) {
+       if (flags & LIBEVDEV_READ_FLAG_SYNC && dev->queue_nsync > 0) {
                dev->queue_nsync--;
-               rc = 1;
+               rc = LIBEVDEV_READ_STATUS_SYNC;
                if (dev->queue_nsync == 0)
                        dev->sync_state = SYNC_NONE;
        }
@@ -748,7 +839,10 @@ libevdev_has_event_pending(struct libevdev *dev)
        struct pollfd fds = { dev->fd, POLLIN, 0 };
        int rc;
 
-       if (dev->fd < 0)
+       if (!dev->initialized) {
+               log_bug("device not initialized. call libevdev_set_fd() first\n");
+               return -EBADF;
+       } else if (dev->fd < 0)
                return -EBADF;
 
        if (queue_num_elements(dev) != 0)
@@ -785,9 +879,9 @@ LIBEVDEV_EXPORT void libevdev_set_##field(struct libevdev *dev, const char *fiel
        dev->field = strdup(field); \
 }
 
-STRING_SETTER(name);
-STRING_SETTER(phys);
-STRING_SETTER(uniq);
+STRING_SETTER(name)
+STRING_SETTER(phys)
+STRING_SETTER(uniq)
 
 
 #define PRODUCT_GETTER(name) \
@@ -796,10 +890,10 @@ LIBEVDEV_EXPORT int libevdev_get_id_##name(const struct libevdev *dev) \
        return dev->ids.name; \
 }
 
-PRODUCT_GETTER(product);
-PRODUCT_GETTER(vendor);
-PRODUCT_GETTER(bustype);
-PRODUCT_GETTER(version);
+PRODUCT_GETTER(product)
+PRODUCT_GETTER(vendor)
+PRODUCT_GETTER(bustype)
+PRODUCT_GETTER(version)
 
 #define PRODUCT_SETTER(field) \
 LIBEVDEV_EXPORT void libevdev_set_id_##field(struct libevdev *dev, int field) \
@@ -807,10 +901,10 @@ LIBEVDEV_EXPORT void libevdev_set_id_##field(struct libevdev *dev, int field) \
        dev->ids.field = field;\
 }
 
-PRODUCT_SETTER(product);
-PRODUCT_SETTER(vendor);
-PRODUCT_SETTER(bustype);
-PRODUCT_SETTER(version);
+PRODUCT_SETTER(product)
+PRODUCT_SETTER(vendor)
+PRODUCT_SETTER(bustype)
+PRODUCT_SETTER(version)
 
 LIBEVDEV_EXPORT int
 libevdev_get_driver_version(const struct libevdev *dev)
@@ -837,7 +931,7 @@ libevdev_enable_property(struct libevdev *dev, unsigned int prop)
 LIBEVDEV_EXPORT int
 libevdev_has_event_type(const struct libevdev *dev, unsigned int type)
 {
-       return (type <= EV_MAX) && bit_is_set(dev->bits, type);
+       return type == EV_SYN ||(type <= EV_MAX && bit_is_set(dev->bits, type));
 }
 
 LIBEVDEV_EXPORT int
@@ -873,6 +967,19 @@ libevdev_get_event_value(const struct libevdev *dev, unsigned int type, unsigned
                case EV_KEY: value = bit_is_set(dev->key_values, code); break;
                case EV_LED: value = bit_is_set(dev->led_values, code); break;
                case EV_SW: value = bit_is_set(dev->sw_values, code); break;
+               case EV_REP:
+                           switch(code) {
+                                   case REP_DELAY:
+                                           libevdev_get_repeat(dev, &value, NULL);
+                                           break;
+                                   case REP_PERIOD:
+                                           libevdev_get_repeat(dev, NULL, &value);
+                                           break;
+                                   default:
+                                           value = 0;
+                                           break;
+                           }
+                           break;
                default:
                        value = 0;
                        break;
@@ -999,11 +1106,11 @@ LIBEVDEV_EXPORT int libevdev_get_abs_##name(const struct libevdev *dev, unsigned
        return absinfo ? absinfo->name : 0; \
 }
 
-ABS_GETTER(maximum);
-ABS_GETTER(minimum);
-ABS_GETTER(fuzz);
-ABS_GETTER(flat);
-ABS_GETTER(resolution);
+ABS_GETTER(maximum)
+ABS_GETTER(minimum)
+ABS_GETTER(fuzz)
+ABS_GETTER(flat)
+ABS_GETTER(resolution)
 
 #define ABS_SETTER(field) \
 LIBEVDEV_EXPORT void libevdev_set_abs_##field(struct libevdev *dev, unsigned int code, int val) \
@@ -1031,12 +1138,18 @@ libevdev_set_abs_info(struct libevdev *dev, unsigned int code, const struct inpu
 LIBEVDEV_EXPORT int
 libevdev_enable_event_type(struct libevdev *dev, unsigned int type)
 {
+       int max;
+
        if (type > EV_MAX)
                return -1;
 
        if (libevdev_has_event_type(dev, type))
                return 0;
 
+       max = libevdev_event_type_get_max(type);
+       if (max == -1)
+               return -1;
+
        set_bit(dev->bits, type);
 
        if (type == EV_REP) {
@@ -1050,9 +1163,15 @@ libevdev_enable_event_type(struct libevdev *dev, unsigned int type)
 LIBEVDEV_EXPORT int
 libevdev_disable_event_type(struct libevdev *dev, unsigned int type)
 {
+       int max;
+
        if (type > EV_MAX || type == EV_SYN)
                return -1;
 
+       max = libevdev_event_type_get_max(type);
+       if (max == -1)
+               return -1;
+
        clear_bit(dev->bits, type);
 
        return 0;
@@ -1084,7 +1203,7 @@ libevdev_enable_event_code(struct libevdev *dev, unsigned int type,
 
        max = type_to_mask(dev, type, &mask);
 
-       if (code > max)
+       if (code > max || (int)max == -1)
                return -1;
 
        set_bit(mask, code);
@@ -1106,12 +1225,12 @@ libevdev_disable_event_code(struct libevdev *dev, unsigned int type, unsigned in
        unsigned int max;
        unsigned long *mask = NULL;
 
-       if (type > EV_MAX)
+       if (type > EV_MAX || type == EV_SYN)
                return -1;
 
        max = type_to_mask(dev, type, &mask);
 
-       if (code > max)
+       if (code > max || (int)max == -1)
                return -1;
 
        clear_bit(mask, code);
@@ -1120,16 +1239,16 @@ libevdev_disable_event_code(struct libevdev *dev, unsigned int type, unsigned in
 }
 
 LIBEVDEV_EXPORT int
-libevdev_kernel_set_abs_value(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs)
-{
-       return libevdev_kernel_set_abs_info(dev, code, abs);
-}
-
-LIBEVDEV_EXPORT int
 libevdev_kernel_set_abs_info(struct libevdev *dev, unsigned int code, const struct input_absinfo *abs)
 {
        int rc;
 
+       if (!dev->initialized) {
+               log_bug("device not initialized. call libevdev_set_fd() first\n");
+               return -EBADF;
+       } else if (dev->fd < 0)
+               return -EBADF;
+
        if (code > ABS_MAX)
                return -EINVAL;
 
@@ -1147,8 +1266,16 @@ libevdev_grab(struct libevdev *dev, enum libevdev_grab_mode grab)
 {
        int rc = 0;
 
-       if (grab != LIBEVDEV_GRAB && grab != LIBEVDEV_UNGRAB)
+       if (!dev->initialized) {
+               log_bug("device not initialized. call libevdev_set_fd() first\n");
+               return -EBADF;
+       } else if (dev->fd < 0)
+               return -EBADF;
+
+       if (grab != LIBEVDEV_GRAB && grab != LIBEVDEV_UNGRAB) {
+               log_bug("invalid grab parameter %#x\n", grab);
                return -EINVAL;
+       }
 
        if (grab == dev->grabbed)
                return 0;
@@ -1165,25 +1292,25 @@ libevdev_grab(struct libevdev *dev, enum libevdev_grab_mode grab)
 }
 
 LIBEVDEV_EXPORT int
-libevdev_is_event_type(const struct input_event *ev, unsigned int type)
+libevdev_event_is_type(const struct input_event *ev, unsigned int type)
 {
        return type < EV_CNT && ev->type == type;
 }
 
 LIBEVDEV_EXPORT int
-libevdev_is_event_code(const struct input_event *ev, unsigned int type, unsigned int code)
+libevdev_event_is_code(const struct input_event *ev, unsigned int type, unsigned int code)
 {
        int max;
 
-       if (!libevdev_is_event_type(ev, type))
+       if (!libevdev_event_is_type(ev, type))
                return 0;
 
-       max = libevdev_get_event_type_max(type);
+       max = libevdev_event_type_get_max(type);
        return (max > -1 && code <= (unsigned int)max && ev->code == code);
 }
 
 LIBEVDEV_EXPORT const char*
-libevdev_get_event_type_name(unsigned int type)
+libevdev_event_type_get_name(unsigned int type)
 {
        if (type > EV_MAX)
                return NULL;
@@ -1192,9 +1319,9 @@ libevdev_get_event_type_name(unsigned int type)
 }
 
 LIBEVDEV_EXPORT const char*
-libevdev_get_event_code_name(unsigned int type, unsigned int code)
+libevdev_event_code_get_name(unsigned int type, unsigned int code)
 {
-       int max = libevdev_get_event_type_max(type);
+       int max = libevdev_event_type_get_max(type);
 
        if (max == -1 || code > (unsigned int)max)
                return NULL;
@@ -1203,7 +1330,7 @@ libevdev_get_event_code_name(unsigned int type, unsigned int code)
 }
 
 LIBEVDEV_EXPORT const char*
-libevdev_get_property_name(unsigned int prop)
+libevdev_property_get_name(unsigned int prop)
 {
        if (prop > INPUT_PROP_MAX)
                return NULL;
@@ -1212,7 +1339,7 @@ libevdev_get_property_name(unsigned int prop)
 }
 
 LIBEVDEV_EXPORT int
-libevdev_get_event_type_max(unsigned int type)
+libevdev_event_type_get_max(unsigned int type)
 {
        if (type > EV_MAX)
                return -1;
@@ -1221,7 +1348,7 @@ libevdev_get_event_type_max(unsigned int type)
 }
 
 LIBEVDEV_EXPORT int
-libevdev_get_repeat(struct libevdev *dev, int *delay, int *period)
+libevdev_get_repeat(const struct libevdev *dev, int *delay, int *period)
 {
        if (!libevdev_has_event_type(dev, EV_REP))
                return -1;
@@ -1250,6 +1377,12 @@ libevdev_kernel_set_led_values(struct libevdev *dev, ...)
        int rc = 0;
        size_t nleds = 0;
 
+       if (!dev->initialized) {
+               log_bug("device not initialized. call libevdev_set_fd() first\n");
+               return -EBADF;
+       } else if (dev->fd < 0)
+               return -EBADF;
+
        memset(ev, 0, sizeof(ev));
 
        va_start(args, dev);
@@ -1296,3 +1429,15 @@ libevdev_kernel_set_led_values(struct libevdev *dev, ...)
 
        return rc;
 }
+
+LIBEVDEV_EXPORT int
+libevdev_set_clock_id(struct libevdev *dev, int clockid)
+{
+       if (!dev->initialized) {
+               log_bug("device not initialized. call libevdev_set_fd() first\n");
+               return -EBADF;
+       } else if (dev->fd < 0)
+               return -EBADF;
+
+       return ioctl(dev->fd, EVIOCSCLOCKID, &clockid) ? -errno : 0;
+}