summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/grail-api.c75
-rw-r--r--src/mtdev-plumbing.h105
-rw-r--r--src/touch-dev.c36
-rw-r--r--src/touch-engine.c7
5 files changed, 215 insertions, 10 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 67f930a..5835897 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,7 +11,7 @@ libgrail_la_SOURCES = \
11 grail-recognizer.c \ 11 grail-recognizer.c \
12 grail-api.c 12 grail-api.c
13 13
14AM_CFLAGS = $(CWARNFLAGS) -std=c99 14AM_CFLAGS = $(CWARNFLAGS) -pthread
15 15
16INCLUDES = -I$(top_srcdir)/include/ 16INCLUDES = -I$(top_srcdir)/include/
17 17
diff --git a/src/grail-api.c b/src/grail-api.c
index 19b66aa..e3b8125 100644
--- a/src/grail-api.c
+++ b/src/grail-api.c
@@ -1,6 +1,8 @@
1#include "grail-inserter.h" 1#include "grail-inserter.h"
2#include "grail-recognizer.h" 2#include "grail-recognizer.h"
3#include <grail.h> 3#include <grail.h>
4#include <pthread.h>
5#include <signal.h>
4#include <string.h> 6#include <string.h>
5#include <stdio.h> 7#include <stdio.h>
6#include <unistd.h> 8#include <unistd.h>
@@ -9,12 +11,48 @@
9#include <errno.h> 11#include <errno.h>
10#include "evbuf.h" 12#include "evbuf.h"
11 13
14static const pthread_mutex_t c_mutex = PTHREAD_MUTEX_INITIALIZER;
15static const pthread_cond_t c_wait = PTHREAD_COND_INITIALIZER;
16
12struct grail_impl { 17struct grail_impl {
13 struct touch_dev dev; 18 struct touch_dev dev;
14 struct touch_engine engine; 19 struct touch_engine engine;
15 struct evbuf evbuf; 20 struct evbuf evbuf;
21 int fd;
22 int pull, finished;
23 pthread_mutex_t mutex;
24 pthread_cond_t wait;
25 pthread_t thread;
16}; 26};
17 27
28/*
29 * While not finished, lock, wait for condition, extract the running
30 * state, unlock, then process the event queue.
31 *
32 * The processing may in principle take seconds to complete without
33 * locking up the writer side.
34 */
35static void *grail_thread(void *priv)
36{
37 struct grail_impl *x = priv;
38 int pull, finished = 0;
39 sigset_t block;
40 sigemptyset(&block);
41 sigaddset(&block, SIGIO);
42 pthread_sigmask(SIG_BLOCK, &block, NULL);
43 while (!finished) {
44 pthread_mutex_lock(&x->mutex);
45 pthread_cond_wait(&x->wait, &x->mutex);
46 pull = x->pull;
47 finished = x->finished;
48 x->pull = 0;
49 pthread_mutex_unlock(&x->mutex);
50 if (!finished && pull)
51 touch_dev_process(&x->dev);
52 }
53 pthread_exit(NULL);
54}
55
18static void tp_event(struct touch_engine *engine, 56static void tp_event(struct touch_engine *engine,
19 const struct input_event *ev) 57 const struct input_event *ev)
20{ 58{
@@ -66,10 +104,18 @@ int grail_open(struct grail *ge, int fd)
66 ret = touch_dev_open(&x->dev, fd); 104 ret = touch_dev_open(&x->dev, fd);
67 if (ret) 105 if (ret)
68 goto freegru; 106 goto freegru;
107 x->fd = fd;
108 x->mutex = c_mutex;
109 x->wait = c_wait;
110 ret = pthread_create(&x->thread, NULL, grail_thread, x);
111 if (ret)
112 goto freetouch;
113 ge->impl = x;
69 touch_engine_init(&x->engine, tp_event, tp_sync, ge); 114 touch_engine_init(&x->engine, tp_event, tp_sync, ge);
70 touch_engine_attach(&x->engine, &x->dev); 115 touch_engine_attach(&x->engine, &x->dev);
71 ge->impl = x;
72 return 0; 116 return 0;
117 freetouch:
118 touch_dev_close(&x->dev, fd);
73 freegru: 119 freegru:
74 gru_destroy(ge); 120 gru_destroy(ge);
75 freedev: 121 freedev:
@@ -82,6 +128,11 @@ int grail_open(struct grail *ge, int fd)
82void grail_close(struct grail *ge, int fd) 128void grail_close(struct grail *ge, int fd)
83{ 129{
84 struct grail_impl *x = ge->impl; 130 struct grail_impl *x = ge->impl;
131 void *status;
132 pthread_mutex_lock(&x->mutex);
133 x->finished = 1;
134 pthread_cond_signal (&x->wait);
135 pthread_mutex_unlock(&x->mutex);
85 touch_engine_detach(&x->engine, &x->dev); 136 touch_engine_detach(&x->engine, &x->dev);
86 touch_dev_close(&x->dev, fd); 137 touch_dev_close(&x->dev, fd);
87 gru_destroy(ge); 138 gru_destroy(ge);
@@ -93,12 +144,28 @@ void grail_close(struct grail *ge, int fd)
93int grail_idle(struct grail *ge, int fd, int ms) 144int grail_idle(struct grail *ge, int fd, int ms)
94{ 145{
95 struct grail_impl *x = ge->impl; 146 struct grail_impl *x = ge->impl;
96 return touch_dev_idle(&x->dev, fd, ms); 147 int ret;
148 pthread_mutex_lock(&x->mutex);
149 ret = touch_dev_idle(&x->dev, fd, ms);
150 pthread_mutex_unlock(&x->mutex);
151 return ret;
97} 152}
98 153
154/*
155 * First extract all input events to a lockless circular buffer, then,
156 * under lock, signal the worker thread.
157 *
158 * This function only blocks temporarily while signalling the worker
159 * thread.
160 */
99int grail_pull(struct grail *ge, int fd) 161int grail_pull(struct grail *ge, int fd)
100{ 162{
101 struct grail_impl *x = ge->impl; 163 struct grail_impl *x = ge->impl;
102 return touch_dev_pull(&x->dev, fd); 164 int finished = touch_dev_fetch(&x->dev, fd) < 0;
165 pthread_mutex_lock(&x->mutex);
166 x->pull = 1;
167 x->finished = finished;
168 pthread_cond_signal(&x->wait);
169 pthread_mutex_unlock(&x->mutex);
170 return 1;
103} 171}
104
diff --git a/src/mtdev-plumbing.h b/src/mtdev-plumbing.h
new file mode 100644
index 0000000..c1d141e
--- /dev/null
+++ b/src/mtdev-plumbing.h
@@ -0,0 +1,105 @@
1/*****************************************************************************
2 *
3 * mtdev - Multitouch Protocol Translation Library (MIT license)
4 *
5 * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
6 * Copyright (C) 2010 Canonical Ltd.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 ****************************************************************************/
28
29#ifndef _MTDEV_PLUMBING_H
30#define _MTDEV_PLUMBING_H
31
32#include <mtdev.h>
33
34/**
35 * mtdev_init - initialize mtdev converter
36 * @dev: the mtdev to initialize
37 *
38 * Sets up the internal data structures.
39 *
40 * Returns zero on success, negative error number otherwise.
41 */
42int mtdev_init(struct mtdev *dev);
43
44/**
45 * mtdev_configure - configure the mtdev converter
46 * @dev: the mtdev to configure
47 * @fd: file descriptor of the kernel device
48 *
49 * Reads the device properties to set up the protocol capabilities.
50 * If preferred, this can be done by hand, omitting this call.
51 *
52 * Returns zero on success, negative error number otherwise.
53 */
54int mtdev_configure(struct mtdev *dev, int fd);
55
56/**
57 * mtdev_fetch_event - fetch an event from the kernel device
58 * @dev: the mtdev in use
59 * @fd: file descriptor of the kernel device
60 * @ev: the kernel input event to fill
61 *
62 * Fetch a kernel event from the kernel device. The read operation
63 * behaves as dictated by the file descriptor; if O_NONBLOCK is not
64 * set, the read will block until an event is available.
65 *
66 * On success, returns the number of events read (0 or 1). Otherwise,
67 * a standard negative error number is returned.
68 */
69int mtdev_fetch_event(struct mtdev *dev, int fd, struct input_event *ev);
70
71/**
72 * mtdev_put_event - put an event into the converter
73 * @dev: the mtdev in use
74 * @ev: the kernel input event to put
75 *
76 * Put a kernel event into the mtdev converter. The event should
77 * come straight from the device.
78 *
79 * This call does not block; if the buffer becomes full, older events
80 * are dropped. The buffer is guaranteed to handle several complete MT
81 * packets.
82 */
83void mtdev_put_event(struct mtdev *dev, const struct input_event *ev);
84
85/**
86 * mtdev_empty - check if there are events to get
87 * @dev: the mtdev in use
88 *
89 * Returns true if the processed event queue is empty, false otherwise.
90 */
91int mtdev_empty(struct mtdev *dev);
92
93/**
94 * mtdev_get_event - get processed events from mtdev
95 * @dev: the mtdev in use
96 * @ev: the input event to fill
97 *
98 * Get a processed event from mtdev. The events appear as if they came
99 * from a type B device emitting MT slot events.
100 *
101 * The queue must be non-empty before calling this function.
102 */
103void mtdev_get_event(struct mtdev *dev, struct input_event* ev);
104
105#endif
diff --git a/src/touch-dev.c b/src/touch-dev.c
index dc23baa..b7efb35 100644
--- a/src/touch-dev.c
+++ b/src/touch-dev.c
@@ -26,6 +26,8 @@
26#include <malloc.h> 26#include <malloc.h>
27#include <string.h> 27#include <string.h>
28#include <errno.h> 28#include <errno.h>
29#include "evbuf.h"
30#include "mtdev-plumbing.h"
29 31
30#define DIM_TOUCH 32 32#define DIM_TOUCH 32
31 33
@@ -35,9 +37,27 @@ struct touch_dev_impl {
35 int status; 37 int status;
36 touch_prop_mask_t mask[1]; 38 touch_prop_mask_t mask[1];
37 touch_prop_t prop[DIM_TOUCH_PROP]; 39 touch_prop_t prop[DIM_TOUCH_PROP];
40 struct evbuf evbuf;
38 struct mtdev mtdev; 41 struct mtdev mtdev;
39}; 42};
40 43
44static int touch_get_fetched(struct touch_dev_impl *x,
45 struct input_event* ev, int ev_max)
46{
47 struct input_event kev;
48 int count = 0;
49 while (count < ev_max) {
50 while (mtdev_empty(&x->mtdev)) {
51 if (evbuf_empty(&x->evbuf))
52 return count;
53 evbuf_get(&x->evbuf, &kev);
54 mtdev_put_event(&x->mtdev, &kev);
55 }
56 mtdev_get_event(&x->mtdev, &ev[count++]);
57 }
58 return count;
59}
60
41static inline int has_any_prop(const touch_prop_mask_t *mask) 61static inline int has_any_prop(const touch_prop_mask_t *mask)
42{ 62{
43 return mask[0] != 0; 63 return mask[0] != 0;
@@ -149,12 +169,24 @@ int touch_dev_idle(struct touch_dev *dev, int fd, int ms)
149 return mtdev_idle(&dev->impl->mtdev, fd, ms); 169 return mtdev_idle(&dev->impl->mtdev, fd, ms);
150} 170}
151 171
152int touch_dev_pull(struct touch_dev *dev, int fd) 172int touch_dev_fetch(struct touch_dev *dev, int fd)
173{
174 struct touch_dev_impl *x = dev->impl;
175 struct input_event ev;
176 int ret, count = 0;
177 while ((ret = mtdev_fetch_event(&x->mtdev, fd, &ev)) > 0) {
178 evbuf_put(&x->evbuf, &ev);
179 count++;
180 }
181 return count > 0 ? count : ret;
182}
183
184int touch_dev_process(struct touch_dev *dev)
153{ 185{
154 struct touch_dev_impl *x = dev->impl; 186 struct touch_dev_impl *x = dev->impl;
155 struct input_event ev; 187 struct input_event ev;
156 int ret, count = 0, consumed; 188 int ret, count = 0, consumed;
157 while ((ret = mtdev_get(&x->mtdev, fd, &ev, 1)) > 0) { 189 while ((ret = touch_get_fetched(x, &ev, 1)) > 0) {
158 consumed = 0; 190 consumed = 0;
159 if (ev.type == EV_SYN) { 191 if (ev.type == EV_SYN) {
160 if (ev.code == SYN_REPORT) 192 if (ev.code == SYN_REPORT)
diff --git a/src/touch-engine.c b/src/touch-engine.c
index 8e43faf..28b68da 100644
--- a/src/touch-engine.c
+++ b/src/touch-engine.c
@@ -40,7 +40,8 @@ static void update_frame(struct touch_frame *frame,
40 struct touch *touch = &frame->touch[slot]; 40 struct touch *touch = &frame->touch[slot];
41 touch->active = active; 41 touch->active = active;
42 if (mask && prop) { 42 if (mask && prop) {
43 for (int i = 0; i < DIM_TOUCH_PROP; i++) 43 int i;
44 for (i = 0; i < DIM_TOUCH_PROP; i++)
44 if (has_prop(mask, i)) 45 if (has_prop(mask, i))
45 touch->prop[i] = prop[i]; 46 touch->prop[i] = prop[i];
46 } 47 }
@@ -48,10 +49,10 @@ static void update_frame(struct touch_frame *frame,
48 49
49static void finalize_frame(struct touch_frame *frame, touch_time_t time) 50static void finalize_frame(struct touch_frame *frame, touch_time_t time)
50{ 51{
51 int last = -1; 52 int i, last = -1;
52 frame->ntouch = 0; 53 frame->ntouch = 0;
53 frame->slot = -1; 54 frame->slot = -1;
54 for (int i = 0; i < DIM_TOUCH_PROP; i++) { 55 for (i = 0; i < DIM_TOUCH_PROP; i++) {
55 frame->touch[i].next = -1; 56 frame->touch[i].next = -1;
56 if (frame->touch[i].active) { 57 if (frame->touch[i].active) {
57 if (last < 0) 58 if (last < 0)