#include "grail-inserter.h" #include "grail-recognizer.h" #include #include #include #include #include #include #include #include #include #include "evbuf.h" static const pthread_mutex_t c_mutex = PTHREAD_MUTEX_INITIALIZER; static const pthread_cond_t c_wait = PTHREAD_COND_INITIALIZER; struct grail_impl { struct touch_dev dev; struct touch_engine engine; struct evbuf evbuf; int fd; int pull, finished; pthread_mutex_t mutex; pthread_cond_t wait; pthread_t thread; }; /* * While not finished, lock, wait for condition, extract the running * state, unlock, then process the event queue. * * The processing may in principle take seconds to complete without * locking up the writer side. */ static void *grail_thread(void *priv) { struct grail_impl *x = priv; int pull, finished = 0; sigset_t block; sigemptyset(&block); sigaddset(&block, SIGIO); pthread_sigmask(SIG_BLOCK, &block, NULL); while (!finished) { pthread_mutex_lock(&x->mutex); pthread_cond_wait(&x->wait, &x->mutex); pull = x->pull; finished = x->finished; x->pull = 0; if (!finished && pull) touch_dev_process(&x->dev); pthread_mutex_unlock(&x->mutex); } pthread_exit(NULL); } static void tp_event(struct touch_engine *engine, const struct input_event *ev) { struct grail *ge = engine->priv; struct grail_impl *x = ge->impl; evbuf_put(&x->evbuf, ev); } static void tp_sync(struct touch_engine *engine, const struct input_event *syn) { struct input_event ev; struct grail *ge = engine->priv; struct grail_impl *x = ge->impl; struct touch_frame *frame = &engine->frame; grail_mask_t filtered[DIM_EV_TYPE_BYTES]; int nevent = 0; gin_frame_begin(ge, frame); gru_recognize(ge, frame); gin_frame_end(ge, filtered, sizeof(filtered), frame); if (!ge->event) { evbuf_clear(&x->evbuf); return; } while (!evbuf_empty(&x->evbuf)) { evbuf_get(&x->evbuf, &ev); if (grail_mask_get(filtered, ev.type)) continue; ge->event(ge, &ev); nevent++; } if (nevent) ge->event(ge, syn); } int grail_open(struct grail *ge, int fd) { struct grail_impl *x; int ret; x = calloc(1, sizeof(*x)); if (!x) return -ENOMEM; ret = gin_init(ge); if (ret) goto freemem; ret = touch_dev_open(&x->dev, fd); if (ret) goto freegin; ret = gru_init(ge, &x->dev.caps); if (ret) goto freedev; x->fd = fd; x->mutex = c_mutex; x->wait = c_wait; ret = pthread_create(&x->thread, NULL, grail_thread, x); if (ret) goto freegru; ge->impl = x; touch_engine_init(&x->engine, tp_event, tp_sync, ge); touch_engine_attach(&x->engine, &x->dev); return 0; freegru: gru_destroy(ge); freedev: touch_dev_close(&x->dev, fd); freegin: gin_destroy(ge); freemem: free(x); return ret; } void grail_close(struct grail *ge, int fd) { struct grail_impl *x = ge->impl; void *status; pthread_mutex_lock(&x->mutex); x->finished = 1; pthread_cond_signal (&x->wait); pthread_mutex_unlock(&x->mutex); touch_engine_detach(&x->engine, &x->dev); gru_destroy(ge); touch_dev_close(&x->dev, fd); gin_destroy(ge); free(ge->impl); ge->impl = 0; } int grail_idle(struct grail *ge, int fd, int ms) { struct grail_impl *x = ge->impl; int ret; pthread_mutex_lock(&x->mutex); ret = touch_dev_idle(&x->dev, fd, ms); pthread_mutex_unlock(&x->mutex); return ret; } /* * First extract all input events to a lockless circular buffer, then, * under lock, signal the worker thread. * * This function only blocks temporarily while signalling the worker * thread. */ int grail_pull(struct grail *ge, int fd) { struct grail_impl *x = ge->impl; pthread_mutex_lock(&x->mutex); x->pull = 1; x->finished = touch_dev_fetch(&x->dev, fd) < 0; pthread_cond_signal(&x->wait); pthread_mutex_unlock(&x->mutex); return 1; }