summaryrefslogtreecommitdiff
path: root/src/core.c
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/core.c
Initial load of mtdev project
Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
Diffstat (limited to 'src/core.c')
-rw-r--r--src/core.c393
1 files changed, 393 insertions, 0 deletions
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}