summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2013-07-02 10:50:37 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2013-07-02 14:02:55 +1000
commitc661e80ba0f20ea8b71fcc0aa02840c52314710a (patch)
tree9a90416818ec37d21fcc44c505b105c5c1fc5a48
parentf3a6b0c6854a59f4433217f279f76383687d0c3b (diff)
downloadlibevdev-c661e80ba0f20ea8b71fcc0aa02840c52314710a.tar.gz
Switch to a state machine to handle incomplete syncs
A caller may start syncing but switch back to normal half-way through the sync. In that case, we need to drop all sync events and continue with regular events only. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--libevdev/libevdev-int.h19
-rw-r--r--libevdev/libevdev.c31
2 files changed, 39 insertions, 11 deletions
diff --git a/libevdev/libevdev-int.h b/libevdev/libevdev-int.h
index 1a4f224..34f8e05 100644
--- a/libevdev/libevdev-int.h
+++ b/libevdev/libevdev-int.h
@@ -51,6 +51,23 @@
_a > _b ? _a : _b; \
})
+/**
+ * Sync state machine:
+ * default state: SYNC_NONE
+ *
+ * SYNC_NONE → SYN_DROPPED or forced sync → SYNC_NEEDED
+ * SYNC_NEEDED → libevdev_next_event(LIBEVDEV_READ_SYNC) → SYNC_IN_PROGRESS
+ * SYNC_NEEDED → libevdev_next_event(LIBEVDEV_READ_SYNC_NONE) → SYNC_NONE
+ * SYNC_IN_PROGRESS → libevdev_next_event(LIBEVDEV_READ_SYNC_NONE) → SYNC_NONE
+ * SYNC_IN_PROGRESS → no sync events left → SYNC_NONE
+ *
+ */
+enum SyncState {
+ SYNC_NONE,
+ SYNC_NEEDED,
+ SYNC_IN_PROGRESS,
+};
+
struct libevdev {
int fd;
libevdev_log_func_t log;
@@ -78,7 +95,7 @@ struct libevdev {
int current_slot;
int rep_values[2];
- int need_sync;
+ enum SyncState sync_state;
int grabbed;
struct input_event *queue;
diff --git a/libevdev/libevdev.c b/libevdev/libevdev.c
index b625934..445cc54 100644
--- a/libevdev/libevdev.c
+++ b/libevdev/libevdev.c
@@ -74,6 +74,7 @@ libevdev_new(void)
dev->current_slot = -1;
dev->log = libevdev_noop_log_func;
dev->grabbed = LIBEVDEV_UNGRAB;
+ dev->sync_state = SYNC_NONE;
return dev;
}
@@ -401,7 +402,7 @@ sync_state(struct libevdev *dev)
/* FIXME: if we have events in the queue after the SYN_DROPPED (which was
queue[0]) we need to shift this backwards. Except that chances are that the
queue may be either full or too full to prepend all the events needed for
- syncing.
+ SYNC_IN_PROGRESS.
so we search for the last sync event in the queue and drop everything before
including that event and rely on the kernel to tell us the right value for that
@@ -429,7 +430,6 @@ sync_state(struct libevdev *dev)
init_event(dev, ev, EV_SYN, SYN_REPORT, 0);
dev->queue_nsync = queue_num_elements(dev);
- dev->need_sync = 0;
return rc;
}
@@ -540,23 +540,32 @@ int libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_e
return -EINVAL;
if (flags & LIBEVDEV_READ_SYNC) {
- if (!dev->need_sync && dev->queue_nsync == 0)
- return -EAGAIN;
- else if (dev->need_sync) {
+ if (dev->sync_state == SYNC_NEEDED) {
rc = sync_state(dev);
if (rc != 0)
return rc;
+ dev->sync_state = SYNC_IN_PROGRESS;
+ }
+
+ if (dev->queue_nsync == 0) {
+ dev->sync_state = SYNC_NONE;
+ return -EAGAIN;
}
- } else if (dev->need_sync) {
+
+ } else if (dev->sync_state != SYNC_NONE) {
struct input_event e;
/* call update_state for all events here, otherwise the library has the wrong view
of the device too */
- while (queue_shift(dev, &e) == 0)
+ while (queue_shift(dev, &e) == 0) {
+ dev->queue_nsync--;
update_state(dev, &e);
+ }
+
+ dev->sync_state = SYNC_NONE;
}
- /* FIXME: if the first event after syncing is a SYN_DROPPED, log this */
+ /* FIXME: if the first event after SYNC_IN_PROGRESS is a SYN_DROPPED, log this */
/* Always read in some more events. Best case this smoothes over a potential SYN_DROPPED,
worst case we don't read fast enough and end up with SYN_DROPPED anyway.
@@ -573,7 +582,7 @@ int libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_e
}
if (flags & LIBEVDEV_FORCE_SYNC) {
- dev->need_sync = 1;
+ dev->sync_state = SYNC_NEEDED;
rc = 1;
goto out;
}
@@ -589,13 +598,15 @@ int libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_e
rc = 0;
if (ev->type == EV_SYN && ev->code == SYN_DROPPED) {
- dev->need_sync = 1;
+ dev->sync_state = SYNC_NEEDED;
rc = 1;
}
if (flags & LIBEVDEV_READ_SYNC && dev->queue_nsync > 0) {
dev->queue_nsync--;
rc = 1;
+ if (dev->queue_nsync == 0)
+ dev->sync_state = SYNC_NONE;
}
out: