summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2010-06-17 18:12:58 +0200
committerHenrik Rydberg <rydberg@euromail.se>2010-06-17 18:12:58 +0200
commit66e5de9eaefc33ffa6af3617f9ec7a50f10af50d (patch)
tree66535311e0b9c422b30341237fd596fb9ebbdd75 /src
Initial load of mtdev project
Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
Diffstat (limited to 'src')
-rw-r--r--src/caps.c103
-rw-r--r--src/common.h87
-rw-r--r--src/core.c393
-rw-r--r--src/evbuf.h64
-rw-r--r--src/iobuf.c69
-rw-r--r--src/iobuf.h42
-rw-r--r--src/match.c392
-rw-r--r--src/match.h43
-rw-r--r--src/state.h62
9 files changed, 1255 insertions, 0 deletions
diff --git a/src/caps.c b/src/caps.c
new file mode 100644
index 0000000..1821bd7
--- /dev/null
+++ b/src/caps.c
@@ -0,0 +1,103 @@
1/*****************************************************************************
2 *
3 * mtdev - MT device event converter (MIT license)
4 *
5 * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
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#include "common.h"
30
31#define SETABS(c, x, map, key, fd) \
32 (c->has_##x = getbit(map, key) && getabs(&c->x, key, fd))
33
34static const int SN_COORD = 250; /* coordinate signal-to-noise ratio */
35static const int SN_WIDTH = 100; /* width signal-to-noise ratio */
36static const int SN_ORIENT = 10; /* orientation signal-to-noise ratio */
37
38static const int bits_per_long = 8 * sizeof(long);
39
40static inline int nlongs(int nbit)
41{
42 return (nbit + bits_per_long - 1) / bits_per_long;
43}
44
45static inline int getbit(const unsigned long *map, int key)
46{
47 return (map[key / bits_per_long] >> (key % bits_per_long)) & 0x01;
48}
49
50static int getabs(struct input_absinfo *abs, int key, int fd)
51{
52 int rc;
53 SYSCALL(rc = ioctl(fd, EVIOCGABS(key), abs));
54 return rc >= 0;
55}
56
57static int has_mt_data(const struct mtdev_caps *cap)
58{
59 return cap->has_abs[MTDEV_POSITION_X] && cap->has_abs[MTDEV_POSITION_Y];
60}
61
62static void default_fuzz(struct mtdev_caps *cap, int bit, int sn)
63{
64 if (cap->has_abs[bit] && cap->abs[bit].fuzz == 0)
65 cap->abs[bit].fuzz =
66 (cap->abs[bit].maximum - cap->abs[bit].minimum) / sn;
67}
68
69static int read_caps(struct mtdev_caps *cap, int fd)
70{
71 unsigned long absbits[nlongs(ABS_MAX)];
72 int rc, i;
73
74 memset(cap, 0, sizeof(struct mtdev_caps));
75
76 SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits));
77 if (rc < 0)
78 return rc;
79
80 SETABS(cap, slot, absbits, ABS_MT_SLOT, fd);
81 for (i = 0; i < MT_ABS_SIZE; i++)
82 SETABS(cap, abs[i], absbits, mtdev_mt2abs(i), fd);
83
84 cap->has_mtdata = has_mt_data(cap);
85
86 if (cap->has_abs[MTDEV_TRACKING_ID])
87 cap->nullid = cap->abs[MTDEV_TRACKING_ID].minimum - 1;
88
89 default_fuzz(cap, MTDEV_POSITION_X, SN_COORD);
90 default_fuzz(cap, MTDEV_POSITION_Y, SN_COORD);
91 default_fuzz(cap, MTDEV_TOUCH_MAJOR, SN_WIDTH);
92 default_fuzz(cap, MTDEV_TOUCH_MINOR, SN_WIDTH);
93 default_fuzz(cap, MTDEV_WIDTH_MAJOR, SN_WIDTH);
94 default_fuzz(cap, MTDEV_WIDTH_MINOR, SN_WIDTH);
95 default_fuzz(cap, MTDEV_ORIENTATION, SN_ORIENT);
96
97 return 0;
98}
99
100int mtdev_configure(struct mtdev *dev, int fd)
101{
102 return read_caps(&dev->caps, fd);
103}
diff --git a/src/common.h b/src/common.h
new file mode 100644
index 0000000..03bc7bd
--- /dev/null
+++ b/src/common.h
@@ -0,0 +1,87 @@
1/*****************************************************************************
2 *
3 * mtdev - MT device event converter (MIT license)
4 *
5 * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
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 COMMON_H
30#define COMMON_H
31
32#include <mtdev-mapping.h>
33#include <malloc.h>
34#include <string.h>
35#include <errno.h>
36
37#define DIM_FINGER 32
38#define DIM2_FINGER (DIM_FINGER * DIM_FINGER)
39
40/* event buffer size (must be a power of two) */
41#define DIM_EVENTS 512
42
43/* all bit masks have this type */
44typedef unsigned int bitmask_t;
45
46#define BITMASK(x) (1U << (x))
47#define BITONES(x) (BITMASK(x) - 1U)
48#define GETBIT(m, x) (((m) >> (x)) & 1U)
49#define SETBIT(m, x) (m |= BITMASK(x))
50#define CLEARBIT(m, x) (m &= ~BITMASK(x))
51#define MODBIT(m, x, b) ((b) ? SETBIT(m, x) : CLEARBIT(m, x))
52
53static inline int maxval(int x, int y) { return x > y ? x : y; }
54static inline int minval(int x, int y) { return x < y ? x : y; }
55
56static inline int clamp15(int x)
57{
58 return x < -32767 ? -32767 : x > 32767 ? 32767 : x;
59}
60
61/* absolute scale is assumed to fit in 15 bits */
62static inline int dist2(int dx, int dy)
63{
64 dx = clamp15(dx);
65 dy = clamp15(dy);
66 return dx * dx + dy * dy;
67}
68
69/* Count number of bits (Sean Eron Andersson's Bit Hacks) */
70static inline int bitcount(unsigned v)
71{
72 v -= ((v>>1) & 0x55555555);
73 v = (v&0x33333333) + ((v>>2) & 0x33333333);
74 return (((v + (v>>4)) & 0xF0F0F0F) * 0x1010101) >> 24;
75}
76
77/* Return index of first bit [0-31], -1 on zero */
78#define firstbit(v) (__builtin_ffs(v) - 1)
79
80/* boost-style foreach bit */
81#define foreach_bit(i, m) \
82 for (i = firstbit(m); i >= 0; i = firstbit((m) & (~0U << i + 1)))
83
84/* robust system ioctl calls */
85#define SYSCALL(call) while (((call) == -1) && (errno == EINTR))
86
87#endif
diff --git a/src/core.c b/src/core.c
new file mode 100644
index 0000000..3df8257
--- /dev/null
+++ b/src/core.c
@@ -0,0 +1,393 @@
1/*****************************************************************************
2 *
3 * mtdev - MT device event converter (MIT license)
4 *
5 * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
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#include "state.h"
30#include "iobuf.h"
31#include "evbuf.h"
32
33static inline int istouch(const struct mtdev_slot *data,
34 const struct mtdev_caps *caps)
35{
36 return data->abs[MTDEV_TOUCH_MAJOR] ||
37 !caps->has_abs[MTDEV_TOUCH_MAJOR];
38}
39
40/* Dmitry Torokhov's code from kernel/driver/input/input.c */
41static int defuzz(int value, int old_val, int fuzz)
42{
43 if (fuzz) {
44 if (value > old_val - fuzz / 2 && value < old_val + fuzz / 2)
45 return old_val;
46
47 if (value > old_val - fuzz && value < old_val + fuzz)
48 return (old_val * 3 + value) / 4;
49
50 if (value > old_val - fuzz * 2 && value < old_val + fuzz * 2)
51 return (old_val + value) / 2;
52 }
53
54 return value;
55}
56
57/*
58 * solve - solve contact matching problem
59 * @state: mtdev state
60 * @caps: device capabilities
61 * @sid: array of current tracking ids
62 * @sx: array of current position x
63 * @sy: array of current position y
64 * @sn: number of current contacts
65 * @nid: array of new or matched tracking ids, to be filled
66 * @nx: array of new position x
67 * @ny: array of new position y
68 * @nn: number of new contacts
69 * @touch: which of the new contacts to fill
70 */
71static void solve(struct mtdev_state *state, const struct mtdev_caps *caps,
72 const int *sid, const int *sx, const int *sy, int sn,
73 int *nid, const int *nx, const int *ny, int nn,
74 bitmask_t touch)
75{
76 int A[DIM2_FINGER], *row;
77 int n2s[DIM_FINGER];
78 int id, i, j;
79
80 /* setup distance matrix for contact matching */
81 for (j = 0; j < sn; j++) {
82 row = A + nn * j;
83 for (i = 0; i < nn; i++)
84 row[i] = dist2(nx[i] - sx[j], ny[i] - sy[j]);
85 }
86
87 match_fingers(n2s, A, nn, sn);
88
89 /* update matched contacts and create new ones */
90 foreach_bit(i, touch) {
91 j = n2s[i];
92 id = j >= 0 ? sid[j] : caps->nullid;
93 while (id == caps->nullid)
94 id = ++state->lastid;
95 nid[i] = id;
96 }
97}
98
99/*
100 * assign_tracking_id - assign tracking ids to all contacts
101 * @state: mtdev state
102 * @caps: device capabilities
103 * @data: array of all present contacts, to be filled
104 * @prop: array of all set contacts properties
105 * @size: number of contacts in array
106 * @touch: which of the contacts are actual touches
107 */
108static void assign_tracking_id(struct mtdev_state *state,
109 const struct mtdev_caps *caps,
110 struct mtdev_slot *data, bitmask_t *prop,
111 int size, bitmask_t touch)
112{
113 int sid[DIM_FINGER], sx[DIM_FINGER], sy[DIM_FINGER], sn = 0;
114 int nid[DIM_FINGER], nx[DIM_FINGER], ny[DIM_FINGER], i;
115 foreach_bit(i, state->used) {
116 sid[sn] = state->data[i].abs[MTDEV_TRACKING_ID];
117 sx[sn] = state->data[i].abs[MTDEV_POSITION_X];
118 sy[sn] = state->data[i].abs[MTDEV_POSITION_Y];
119 sn++;
120 }
121 for (i = 0; i < size; i++) {
122 nx[i] = data[i].abs[MTDEV_POSITION_X];
123 ny[i] = data[i].abs[MTDEV_POSITION_Y];
124 }
125 solve(state, caps, sid, sx, sy, sn, nid, nx, ny, size, touch);
126 for (i = 0; i < size; i++) {
127 data[i].abs[MTDEV_TRACKING_ID] =
128 GETBIT(touch, i) ? nid[i] : caps->nullid;
129 prop[i] |= BITMASK(MTDEV_TRACKING_ID);
130 }
131}
132
133/*
134 * process_typeA - consume MT events and update mtdev state
135 * @state: mtdev state
136 * @data: array of all present contacts, to be filled
137 * @prop: array of all set contacts properties, to be filled
138 *
139 * This function is called when a SYN_REPORT is seen, right before
140 * that event is pushed to the queue.
141 *
142 * Returns -1 if the packet is not MT related and should not affect
143 * the current mtdev state.
144 */
145static int process_typeA(struct mtdev_state *state,
146 struct mtdev_slot *data, bitmask_t *prop)
147{
148 struct input_event ev;
149 int consumed, mtcode;
150 int mtcnt = 0, size = 0;
151 prop[size] = 0;
152 while (!evbuf_empty(&state->inbuf)) {
153 evbuf_get(&state->inbuf, &ev);
154 consumed = 0;
155 switch (ev.type) {
156 case EV_SYN:
157 switch (ev.code) {
158 case SYN_MT_REPORT:
159 if (size < DIM_FINGER &&
160 GETBIT(prop[size], MTDEV_POSITION_X) &&
161 GETBIT(prop[size], MTDEV_POSITION_Y))
162 size++;
163 if (size < DIM_FINGER)
164 prop[size] = 0;
165 mtcnt++;
166 consumed = 1;
167 break;
168 }
169 break;
170 case EV_KEY:
171 switch (ev.code) {
172 case BTN_TOUCH:
173 mtcnt++;
174 break;
175 }
176 break;
177 case EV_ABS:
178 if (size < DIM_FINGER && mtdev_is_absmt(ev.code)) {
179 mtcode = mtdev_abs2mt(ev.code);
180 data[size].abs[mtcode] = ev.value;
181 prop[size] |= BITMASK(mtcode);
182 mtcnt++;
183 consumed = 1;
184 }
185 break;
186 }
187 if (!consumed)
188 evbuf_put(&state->outbuf, &ev);
189 }
190 return mtcnt ? size : -1;
191}
192
193/*
194 * process_typeB - propagate events without parsing
195 * @state: mtdev state
196 *
197 * This function is called when a SYN_REPORT is seen, right before
198 * that event is pushed to the queue.
199 */
200static void process_typeB(struct mtdev_state *state)
201{
202 struct input_event ev;
203 while (!evbuf_empty(&state->inbuf)) {
204 evbuf_get(&state->inbuf, &ev);
205 evbuf_put(&state->outbuf, &ev);
206 }
207}
208
209/*
210 * filter_data - apply input filtering on new incoming data
211 * @state: mtdev state
212 * @caps: device capabilities
213 * @data: the incoming data to filter
214 * @prop: the properties to filter
215 * @slot: the slot the data refers to
216 */
217static void filter_data(const struct mtdev_state *state,
218 const struct mtdev_caps *caps,
219 struct mtdev_slot *data, bitmask_t prop,
220 int slot)
221{
222 int i;
223 foreach_bit(i, prop) {
224 int fuzz = caps->abs[i].fuzz;
225 int oldval = state->data[slot].abs[i];
226 data->abs[i] = defuzz(data->abs[i], oldval, fuzz);
227 }
228}
229
230/*
231 * push_slot_changes - propagate state changes
232 * @state: mtdev state
233 * @data: the incoming data to propagate
234 * @prop: the properties to propagate
235 * @slot: the slot the data refers to
236 * @syn: reference to the SYN_REPORT event
237 */
238static void push_slot_changes(struct mtdev_state *state,
239 const struct mtdev_slot *data, bitmask_t prop,
240 int slot, const struct input_event *syn)
241{
242 struct input_event ev;
243 int i, count = 0;
244 foreach_bit(i, prop)
245 if (state->data[slot].abs[i] != data->abs[i])
246 count++;
247 if (!count)
248 return;
249 ev.time = syn->time;
250 ev.type = EV_ABS;
251 ev.code = ABS_MT_SLOT;
252 ev.value = slot;
253 if (state->slot != ev.value) {
254 evbuf_put(&state->outbuf, &ev);
255 state->slot = ev.value;
256 }
257 foreach_bit(i, prop) {
258 ev.code = mtdev_mt2abs(i);
259 ev.value = data->abs[i];
260 if (state->data[slot].abs[i] != ev.value) {
261 evbuf_put(&state->outbuf, &ev);
262 state->data[slot].abs[i] = ev.value;
263 }
264 }
265}
266
267/*
268 * apply_typeA_changes - parse and propagate state changes
269 * @state: mtdev state
270 * @caps: device capabilities
271 * @data: array of data to apply
272 * @prop: array of properties to apply
273 * @size: number of contacts in array
274 * @syn: reference to the SYN_REPORT event
275 */
276static void apply_typeA_changes(struct mtdev_state *state,
277 const struct mtdev_caps *caps,
278 struct mtdev_slot *data, const bitmask_t *prop,
279 int size, const struct input_event *syn)
280{
281 bitmask_t unused = ~state->used;
282 bitmask_t used = 0;
283 int i, slot, id;
284 for (i = 0; i < size; i++) {
285 id = data[i].abs[MTDEV_TRACKING_ID];
286 foreach_bit(slot, state->used) {
287 if (state->data[slot].abs[MTDEV_TRACKING_ID] != id)
288 continue;
289 filter_data(state, caps, &data[i], prop[i], slot);
290 push_slot_changes(state, &data[i], prop[i], slot, syn);
291 SETBIT(used, slot);
292 id = caps->nullid;
293 break;
294 }
295 if (id != caps->nullid) {
296 slot = firstbit(unused);
297 push_slot_changes(state, &data[i], prop[i], slot, syn);
298 SETBIT(used, slot);
299 CLEARBIT(unused, slot);
300 }
301 }
302
303 /* clear unused slots and update slot usage */
304 foreach_bit(slot, state->used & ~used) {
305 struct mtdev_slot tdata = state->data[slot];
306 bitmask_t tprop = BITMASK(MTDEV_TRACKING_ID);
307 tdata.abs[MTDEV_TRACKING_ID] = caps->nullid;
308 push_slot_changes(state, &tdata, tprop, slot, syn);
309 }
310 state->used = used;
311}
312
313/*
314 * convert_A_to_B - propagate a type A packet as a type B packet
315 * @state: mtdev state
316 * @caps: device capabilities
317 * @syn: reference to the SYN_REPORT event
318 */
319static void convert_A_to_B(struct mtdev_state *state,
320 const struct mtdev_caps *caps,
321 const struct input_event *syn)
322{
323 struct mtdev_slot data[DIM_FINGER];
324 bitmask_t prop[DIM_FINGER];
325 int size = process_typeA(state, data, prop);
326 if (size < 0)
327 return;
328 if (!caps->has_abs[MTDEV_TRACKING_ID]) {
329 bitmask_t touch = 0;
330 int i;
331 for (i = 0; i < size; i++)
332 MODBIT(touch, i, istouch(&data[i], caps));
333 assign_tracking_id(state, caps, data, prop, size, touch);
334 }
335 apply_typeA_changes(state, caps, data, prop, size, syn);
336}
337
338int mtdev_init(struct mtdev *dev)
339{
340 memset(dev, 0, sizeof(struct mtdev));
341 dev->state = calloc(1, sizeof(struct mtdev_state));
342 if (!dev->state)
343 return -ENOMEM;
344 return 0;
345}
346
347int mtdev_open(struct mtdev *dev, int fd)
348{
349 int ret;
350 ret = mtdev_init(dev);
351 if (ret)
352 goto error;
353 ret = mtdev_configure(dev, fd);
354 if (ret)
355 goto mtdev;
356 return 0;
357 mtdev:
358 mtdev_close(dev);
359 error:
360 return ret;
361}
362
363void mtdev_put(struct mtdev *dev, const struct input_event *ev)
364{
365 struct mtdev_state *state = dev->state;
366 if (ev->type == EV_SYN && ev->code == SYN_REPORT) {
367 bitmask_t head = state->outbuf.head;
368 if (dev->state)
369 convert_A_to_B(state, &dev->caps, ev);
370 else
371 process_typeB(state);
372 if (state->outbuf.head != head)
373 evbuf_put(&state->outbuf, ev);
374 } else {
375 evbuf_put(&state->inbuf, ev);
376 }
377}
378
379int mtdev_empty(struct mtdev *dev)
380{
381 return evbuf_empty(&dev->state->outbuf);
382}
383
384void mtdev_get(struct mtdev *dev, struct input_event* ev)
385{
386 evbuf_get(&dev->state->outbuf, ev);
387}
388
389void mtdev_close(struct mtdev *dev)
390{
391 free(dev->state);
392 memset(dev, 0, sizeof(struct mtdev));
393}
diff --git a/src/evbuf.h b/src/evbuf.h
new file mode 100644
index 0000000..ba61cd5
--- /dev/null
+++ b/src/evbuf.h
@@ -0,0 +1,64 @@
1/*****************************************************************************
2 *
3 * mtdev - MT device event converter (MIT license)
4 *
5 * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
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_EVBUF_H
30#define MTDEV_EVBUF_H
31
32#include "common.h"
33
34struct mtdev_evbuf {
35 int head;
36 int tail;
37 struct input_event buffer[DIM_EVENTS];
38};
39
40static inline int evbuf_empty(const struct mtdev_evbuf *evbuf)
41{
42 return evbuf->head == evbuf->tail;
43}
44
45static inline int evbuf_full(const struct mtdev_evbuf *evbuf)
46{
47 return ((evbuf->head + 1) & (DIM_EVENTS - 1)) == evbuf->tail;
48}
49
50static inline void evbuf_put(struct mtdev_evbuf *evbuf,
51 const struct input_event *ev)
52{
53 evbuf->buffer[evbuf->head++] = *ev;
54 evbuf->head &= DIM_EVENTS - 1;
55}
56
57static inline void evbuf_get(struct mtdev_evbuf *evbuf,
58 struct input_event *ev)
59{
60 *ev = evbuf->buffer[evbuf->tail++];
61 evbuf->tail &= DIM_EVENTS - 1;
62}
63
64#endif
diff --git a/src/iobuf.c b/src/iobuf.c
new file mode 100644
index 0000000..6d238ec
--- /dev/null
+++ b/src/iobuf.c
@@ -0,0 +1,69 @@
1/*****************************************************************************
2 *
3 * mtdev - MT device event converter (MIT license)
4 *
5 * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
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#include "iobuf.h"
30#include "state.h"
31
32int mtdev_fetch(struct mtdev *dev, struct input_event *ev, int fd)
33{
34 struct mtdev_iobuf *buf = &dev->state->iobuf;
35 int n = buf->head - buf->tail;
36 if (n < EVENT_SIZE) {
37 if (buf->tail && n > 0)
38 memmove(buf->data, buf->data + buf->tail, n);
39 buf->head = n;
40 buf->tail = 0;
41 SYSCALL(n = read(fd, buf->data + buf->head,
42 DIM_BUFFER - buf->head));
43 if (n <= 0)
44 return n;
45 buf->head += n;
46 }
47 if (buf->head - buf->tail < EVENT_SIZE)
48 return 0;
49 memcpy(ev, buf->data + buf->tail, EVENT_SIZE);
50 buf->tail += EVENT_SIZE;
51 return 1;
52}
53
54int mtdev_pull(struct mtdev *dev, int fd, int max_events)
55{
56 struct mtdev_state *state = dev->state;
57 struct input_event ev;
58 int ret, count = 0;
59 while (max_events-- && !evbuf_full(&state->inbuf)) {
60 ret = mtdev_fetch(dev, &ev, fd);
61 if (ret < 0)
62 return ret;
63 if (ret == 0)
64 break;
65 mtdev_put(dev, &ev);
66 count++;
67 }
68 return count;
69}
diff --git a/src/iobuf.h b/src/iobuf.h
new file mode 100644
index 0000000..b54ea48
--- /dev/null
+++ b/src/iobuf.h
@@ -0,0 +1,42 @@
1/*****************************************************************************
2 *
3 * mtdev - MT device event converter (MIT license)
4 *
5 * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
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_IOBUF_H
30#define MTDEV_IOBUF_H
31
32#include "common.h"
33
34#define EVENT_SIZE sizeof(struct input_event)
35#define DIM_BUFFER (DIM_EVENTS * EVENT_SIZE)
36
37struct mtdev_iobuf {
38 int head, tail;
39 char data[DIM_BUFFER];
40};
41
42#endif
diff --git a/src/match.c b/src/match.c
new file mode 100644
index 0000000..1b3700c
--- /dev/null
+++ b/src/match.c
@@ -0,0 +1,392 @@
1/*****************************************************************************
2 *
3 * mtdev - MT device event converter (MIT license)
4 *
5 * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
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#include "match.h"
30#include <string.h>
31#include <stdio.h>
32
33/**
34 * Bitmap implementation of the hungarian algorithm (GPL license)
35 *
36 * Copyright (C) 2008 Henrik Rydberg <rydberg@euromail.se>
37 *
38 * Based on code released by Markus Buehren (2004) (BSD license)
39 *
40 * Copyright (C) 2004, Markus Buehren. All rights reserved.
41 * See CREDITS file for full license terms.
42 *
43 */
44
45typedef unsigned col_t[1];
46typedef unsigned mat_t[DIM_FINGER];
47
48#define GET1(m, x) ((m[0] >> (x)) & 1U)
49#define SET1(m, x) (m[0] |= (1U << (x)))
50#define CLEAR1(m, x) (m[0] &= ~(1U << (x)))
51
52#define GET2(m, row, col) ((m[col] >> (row)) & 1U)
53#define SET2(m, row, col) (m[col] |= (1U << (row)))
54#define CLEAR2(m, row, col) (m[col] &= ~(1U << (row)))
55
56/********************************************************/
57
58static void buildixvector(int *ix, mat_t mstar, int nrows, int ncols)
59{
60 int row, col;
61 for (row = 0; row < nrows; row++) {
62 for (col = 0; col < ncols; col++) {
63 if (GET2(mstar, row, col)) {
64 ix[row] = col;
65 break;
66 }
67 }
68 }
69}
70
71
72/********************************************************/
73
74static void step2a(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
75 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
76 int dmin);
77static void step2b(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
78 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
79 int dmin);
80static void step3(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
81 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
82 int dmin);
83static void step4(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
84 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
85 int dmin, int row, int col);
86static void step5(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
87 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
88 int dmin);
89
90static void ixoptimal(int *ix, int *mdist, int nrows, int ncols)
91{
92 int *mdistTemp, *mdistEnd, *columnEnd, value, minValue;
93 int dmin, row, col;
94 col_t ccol, crow;
95 mat_t mstar, mprime, nmstar;
96
97 memset(ccol, 0, sizeof(col_t));
98 memset(crow, 0, sizeof(col_t));
99 memset(mstar, 0, sizeof(mat_t));
100 memset(mprime, 0, sizeof(mat_t));
101 memset(nmstar, 0, sizeof(mat_t));
102
103 /* initialization */
104 for (row = 0; row < nrows; row++)
105 ix[row] = -1;
106
107 mdistEnd = mdist + nrows * ncols;
108
109 /* preliminary steps */
110 if (nrows <= ncols) {
111 dmin = nrows;
112
113 for (row = 0; row < nrows; row++) {
114 /* find the smallest element in the row */
115 mdistTemp = mdist + row;
116 minValue = *mdistTemp;
117 mdistTemp += nrows;
118 while (mdistTemp < mdistEnd) {
119 value = *mdistTemp;
120 if (value < minValue)
121 minValue = value;
122 mdistTemp += nrows;
123 }
124
125 /* subtract the smallest element from each element
126 of the row */
127 mdistTemp = mdist + row;
128 while (mdistTemp < mdistEnd) {
129 *mdistTemp -= minValue;
130 mdistTemp += nrows;
131 }
132 }
133
134 /* Steps 1 and 2a */
135 for (row = 0; row < nrows; row++) {
136 for (col = 0; col < ncols; col++) {
137 if (mdist[row + nrows * col] != 0)
138 continue;
139 if (GET1(ccol, col))
140 continue;
141 SET2(mstar, row, col);
142 SET1(ccol, col);
143 break;
144 }
145 }
146 } else {
147 dmin = ncols;
148
149 for (col = 0; col < ncols; col++) {
150 /* find the smallest element in the column */
151 mdistTemp = mdist + nrows*col;
152 columnEnd = mdistTemp + nrows;
153
154 minValue = *mdistTemp++;
155 while (mdistTemp < columnEnd) {
156 value = *mdistTemp++;
157 if (value < minValue)
158 minValue = value;
159 }
160
161 /* subtract the smallest element from each element
162 of the column */
163 mdistTemp = mdist + nrows*col;
164 while (mdistTemp < columnEnd)
165 *mdistTemp++ -= minValue;
166 }
167
168 /* Steps 1 and 2a */
169 for (col = 0; col < ncols; col++) {
170 for (row = 0; row < nrows; row++) {
171 if (mdist[row + nrows * col] != 0)
172 continue;
173 if (GET1(crow, row))
174 continue;
175 SET2(mstar, row, col);
176 SET1(ccol, col);
177 SET1(crow, row);
178 break;
179 }
180 }
181 memset(crow, 0, sizeof(col_t));
182 }
183
184 /* move to step 2b */
185 step2b(ix, mdist, mstar, nmstar,
186 mprime, ccol, crow, nrows, ncols,
187 dmin);
188}
189
190/********************************************************/
191static void step2a(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
192 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
193 int dmin)
194{
195 int col, row;
196
197 /* cover every column containing a starred zero */
198 for (col = 0; col < ncols; col++) {
199 for (row = 0; row < nrows; row++) {
200 if (!GET2(mstar, row, col))
201 continue;
202 SET1(ccol, col);
203 break;
204 }
205 }
206
207 /* move to step 3 */
208 step2b(ix, mdist, mstar, nmstar,
209 mprime, ccol, crow, nrows, ncols,
210 dmin);
211}
212
213/********************************************************/
214static void step2b(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
215 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
216 int dmin)
217{
218 int col, ncc;
219
220 /* count covered columns */
221 ncc = 0;
222 for (col = 0; col < ncols; col++)
223 if (GET1(ccol, col))
224 ncc++;
225
226 if (ncc == dmin) {
227 /* algorithm finished */
228 buildixvector(ix, mstar, nrows, ncols);
229 } else {
230 /* move to step 3 */
231 step3(ix, mdist, mstar, nmstar,
232 mprime, ccol, crow, nrows, ncols,
233 dmin);
234 }
235
236}
237
238/********************************************************/
239static void step3(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
240 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
241 int dmin)
242{
243 int zerosFound;
244 int row, col, cstar;
245
246 zerosFound = 1;
247 while (zerosFound) {
248 zerosFound = 0;
249 for (col = 0; col < ncols; col++) {
250 if (GET1(ccol, col))
251 continue;
252 for (row = 0; row < nrows; row++) {
253 if (mdist[row + nrows * col] != 0)
254 continue;
255 if (GET1(crow, row))
256 continue;
257
258 /* prime zero */
259 SET2(mprime, row, col);
260
261 /* find starred zero in current row */
262 for (cstar = 0; cstar < ncols; cstar++)
263 if (GET2(mstar, row, cstar))
264 break;
265
266 if (cstar == ncols) { /* no starred zero */
267 /* move to step 4 */
268 step4(ix, mdist, mstar, nmstar,
269 mprime, ccol, crow, nrows, ncols,
270 dmin, row, col);
271 return;
272 } else {
273 SET1(crow, row);
274 CLEAR1(ccol, cstar);
275 zerosFound = 1;
276 break;
277 }
278 }
279 }
280 }
281
282 /* move to step 5 */
283 step5(ix, mdist, mstar, nmstar,
284 mprime, ccol, crow, nrows, ncols,
285 dmin);
286}
287
288/********************************************************/
289static void step4(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
290 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
291 int dmin, int row, int col)
292{
293 int n, rstar, cstar, primeRow, primeCol;
294
295 /* generate temporary copy of mstar */
296 memcpy(nmstar, mstar, sizeof(mat_t));
297
298 /* star current zero */
299 SET2(nmstar, row, col);
300
301 /* find starred zero in current column */
302 cstar = col;
303 for (rstar = 0; rstar < nrows; rstar++)
304 if (GET2(mstar, rstar, cstar))
305 break;
306
307 while (rstar < nrows) {
308 /* unstar the starred zero */
309 CLEAR2(nmstar, rstar, cstar);
310
311 /* find primed zero in current row */
312 primeRow = rstar;
313 for (primeCol = 0; primeCol < ncols; primeCol++)
314 if (GET2(mprime, primeRow, primeCol))
315 break;
316
317 /* star the primed zero */
318 SET2(nmstar, primeRow, primeCol);
319
320 /* find starred zero in current column */
321 cstar = primeCol;
322 for (rstar = 0; rstar < nrows; rstar++)
323 if (GET2(mstar, rstar, cstar))
324 break;
325 }
326
327 /* use temporary copy as new mstar */
328 /* delete all primes, uncover all rows */
329 memcpy(mstar, nmstar, sizeof(mat_t));
330 memset(mprime, 0, sizeof(mat_t));
331 memset(crow, 0, sizeof(col_t));
332
333 /* move to step 2a */
334 step2a(ix, mdist, mstar, nmstar,
335 mprime, ccol, crow, nrows, ncols,
336 dmin);
337}
338
339/********************************************************/
340static void step5(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
341 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
342 int dmin)
343{
344 int h = 0, value;
345 int row, col, found = 0;
346
347 /* find smallest uncovered element h */
348 for (row = 0; row < nrows; row++) {
349 if (GET1(crow, row))
350 continue;
351 for (col = 0; col < ncols; col++) {
352 if (GET1(ccol, col))
353 continue;
354 value = mdist[row + nrows * col];
355 if (!found || value < h) {
356 h = value;
357 found = 1;
358 }
359 }
360 }
361
362 /* where to go if nothing uncovered? */
363 if (!found)
364 return;
365
366 /* add h to each covered row */
367 for (row = 0; row < nrows; row++) {
368 if (!GET1(crow, row))
369 continue;
370 for (col = 0; col < ncols; col++)
371 mdist[row + nrows * col] += h;
372 }
373
374 /* subtract h from each uncovered column */
375 for (col = 0; col < ncols; col++) {
376 if (GET1(ccol, col))
377 continue;
378 for (row = 0; row < nrows; row++)
379 mdist[row + nrows * col] -= h;
380 }
381
382 /* move to step 3 */
383 step3(ix, mdist, mstar, nmstar,
384 mprime, ccol, crow, nrows, ncols,
385 dmin);
386}
387
388void match_fingers(int ix[DIM_FINGER], int A[DIM2_FINGER], int nrow, int ncol)
389{
390 ixoptimal(ix, A, nrow, ncol);
391}
392
diff --git a/src/match.h b/src/match.h
new file mode 100644
index 0000000..e6d7d73
--- /dev/null
+++ b/src/match.h
@@ -0,0 +1,43 @@
1/*****************************************************************************
2 *
3 * mtdev - MT device event converter (MIT license)
4 *
5 * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
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 MATCHER_H
30#define MATCHER_H
31
32/**
33 * Special implementation of the hungarian algorithm.
34 * The maximum number of fingers matches a uint32.
35 * Bitmasks are used extensively.
36 */
37
38#include "common.h"
39
40void match_fingers(int index[DIM_FINGER], int A[DIM2_FINGER],
41 int nrow, int ncol);
42
43#endif
diff --git a/src/state.h b/src/state.h
new file mode 100644
index 0000000..37ac803
--- /dev/null
+++ b/src/state.h
@@ -0,0 +1,62 @@
1/*****************************************************************************
2 *
3 * mtdev - MT device event converter (MIT license)
4 *
5 * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
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_STATE_H
30#define MTDEV_STATE_H
31
32#include "iobuf.h"
33#include "evbuf.h"
34
35/*
36 * struct mtdev_slot - represents the state of an input MT slot
37 * @abs: current values of ABS_MT axes for this slot
38 */
39struct mtdev_slot {
40 int abs[MT_ABS_SIZE];
41};
42
43/*
44 * struct mtdev_state - MT slot parsing
45 * @inbuf: input event buffer
46 * @outbuf: output event buffer
47 * @data: array of scratch slot data
48 * @used: bitmask of currently used slots
49 * @slot: slot currently being modified
50 * @lastid: last used tracking id
51 */
52struct mtdev_state {
53 struct mtdev_iobuf iobuf;
54 struct mtdev_evbuf inbuf;
55 struct mtdev_evbuf outbuf;
56 struct mtdev_slot data[DIM_FINGER];
57 bitmask_t used;
58 bitmask_t slot;
59 bitmask_t lastid;
60};
61
62#endif