• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*****************************************************************************
2  *
3  * mtdev - Multitouch Protocol Translation Library (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 #include "match.h"
33 
34 #ifndef input_event_sec
35 #define input_event_sec time.tv_sec
36 #define input_event_usec time.tv_usec
37 #endif
38 
istouch(const struct mtdev_slot * data,const struct mtdev * dev)39 static inline int istouch(const struct mtdev_slot *data,
40 			  const struct mtdev *dev)
41 {
42 	return data->touch_major ||
43 		!mtdev_has_mt_event(dev, ABS_MT_TOUCH_MAJOR);
44 }
45 
isfilled(unsigned int mask)46 static inline int isfilled(unsigned int mask)
47 {
48 	return GETBIT(mask, mtdev_abs2mt(ABS_MT_POSITION_X)) &&
49 		GETBIT(mask, mtdev_abs2mt(ABS_MT_POSITION_Y));
50 }
51 
52 /* Response-augmented EWMA filter, courtesy of Vojtech Pavlik */
defuzz(int value,int old_val,int fuzz)53 static int defuzz(int value, int old_val, int fuzz)
54 {
55 	if (fuzz) {
56 		if (value > old_val - fuzz / 2 && value < old_val + fuzz / 2)
57 			return old_val;
58 
59 		if (value > old_val - fuzz && value < old_val + fuzz)
60 			return (old_val * 3 + value) / 4;
61 
62 		if (value > old_val - fuzz * 2 && value < old_val + fuzz * 2)
63 			return (old_val + value) / 2;
64 	}
65 
66 	return value;
67 }
68 
69 /*
70  * solve - solve contact matching problem
71  * @state: mtdev state
72  * @dev: device capabilities
73  * @sid: array of current tracking ids
74  * @sx: array of current position x
75  * @sy: array of current position y
76  * @sn: number of current contacts
77  * @nid: array of new or matched tracking ids, to be filled
78  * @nx: array of new position x
79  * @ny: array of new position y
80  * @nn: number of new contacts
81  * @touch: which of the new contacts to fill
82  */
solve(struct mtdev_state * state,const struct mtdev * dev,const int * sid,const int * sx,const int * sy,int sn,int * nid,const int * nx,const int * ny,int nn,bitmask_t touch)83 static void solve(struct mtdev_state *state, const struct mtdev *dev,
84 		  const int *sid, const int *sx, const int *sy, int sn,
85 		  int *nid, const int *nx, const int *ny, int nn,
86 		  bitmask_t touch)
87 {
88 	int A[DIM2_FINGER], *row;
89 	int n2s[DIM_FINGER];
90 	int id, i, j;
91 
92 	/* setup distance matrix for contact matching */
93 	for (j = 0; j < sn; j++) {
94 		row = A + nn * j;
95 		for (i = 0; i < nn; i++)
96 			row[i] = dist2(nx[i] - sx[j], ny[i] - sy[j]);
97 	}
98 
99 	mtdev_match(n2s, A, nn, sn);
100 
101 	/* update matched contacts and create new ones */
102 	foreach_bit(i, touch) {
103 		j = n2s[i];
104 		id = j >= 0 ? sid[j] : MT_ID_NULL;
105 		if (id == MT_ID_NULL)
106 			id = state->lastid++ & MT_ID_MAX;
107 		nid[i] = id;
108 	}
109 }
110 
111 /*
112  * assign_tracking_id - assign tracking ids to all contacts
113  * @state: mtdev state
114  * @dev: device capabilities
115  * @data: array of all present contacts, to be filled
116  * @prop: array of all set contacts properties
117  * @size: number of contacts in array
118  * @touch: which of the contacts are actual touches
119  */
assign_tracking_id(struct mtdev_state * state,const struct mtdev * dev,struct mtdev_slot * data,bitmask_t * prop,int size,bitmask_t touch)120 static void assign_tracking_id(struct mtdev_state *state,
121 			       const struct mtdev *dev,
122 			       struct mtdev_slot *data, bitmask_t *prop,
123 			       int size, bitmask_t touch)
124 {
125 	int sid[DIM_FINGER], sx[DIM_FINGER], sy[DIM_FINGER], sn = 0;
126 	int nid[DIM_FINGER], nx[DIM_FINGER], ny[DIM_FINGER], i;
127 	foreach_bit(i, state->used) {
128 		sid[sn] = state->data[i].tracking_id;
129 		sx[sn] = state->data[i].position_x;
130 		sy[sn] = state->data[i].position_y;
131 		sn++;
132 	}
133 	for (i = 0; i < size; i++) {
134 		nx[i] = data[i].position_x;
135 		ny[i] = data[i].position_y;
136 	}
137 	solve(state, dev, sid, sx, sy, sn, nid, nx, ny, size, touch);
138 	for (i = 0; i < size; i++) {
139 		data[i].tracking_id = GETBIT(touch, i) ? nid[i] : MT_ID_NULL;
140 		SETBIT(prop[i], mtdev_abs2mt(ABS_MT_TRACKING_ID));
141 	}
142 }
143 
144 /*
145  * process_typeA - consume MT events and update mtdev state
146  * @state: mtdev state
147  * @data: array of all present contacts, to be filled
148  * @prop: array of all set contacts properties, to be filled
149  *
150  * This function is called when a SYN_REPORT is seen, right before
151  * that event is pushed to the queue.
152  *
153  * Returns -1 if the packet is not MT related and should not affect
154  * the current mtdev state.
155  */
process_typeA(struct mtdev_state * state,struct mtdev_slot * data,bitmask_t * prop)156 static int process_typeA(struct mtdev_state *state,
157 			 struct mtdev_slot *data, bitmask_t *prop)
158 {
159 	struct input_event ev;
160 	int consumed, mtcode;
161 	int mtcnt = 0, size = 0;
162 	prop[size] = 0;
163 	while (!evbuf_empty(&state->inbuf)) {
164 		evbuf_get(&state->inbuf, &ev);
165 		consumed = 0;
166 		switch (ev.type) {
167 		case EV_SYN:
168 			switch (ev.code) {
169 			case SYN_MT_REPORT:
170 				if (size < DIM_FINGER && isfilled(prop[size]))
171 					size++;
172 				if (size < DIM_FINGER)
173 					prop[size] = 0;
174 				mtcnt++;
175 				consumed = 1;
176 				break;
177 			}
178 			break;
179 		case EV_KEY:
180 			switch (ev.code) {
181 			case BTN_TOUCH:
182 				mtcnt++;
183 				break;
184 			}
185 			break;
186 		case EV_ABS:
187 			if (size < DIM_FINGER && mtdev_is_absmt(ev.code)) {
188 				mtcode = mtdev_abs2mt(ev.code);
189 				set_sval(&data[size], mtcode, ev.value);
190 				SETBIT(prop[size], mtcode);
191 				mtcnt++;
192 				consumed = 1;
193 			}
194 			break;
195 		}
196 		if (!consumed)
197 			evbuf_put(&state->outbuf, &ev);
198 	}
199 	return mtcnt ? size : -1;
200 }
201 
202 /*
203  * process_typeB - propagate events without parsing
204  * @state: mtdev state
205  *
206  * This function is called when a SYN_REPORT is seen, right before
207  * that event is pushed to the queue.
208  */
process_typeB(struct mtdev_state * state)209 static void process_typeB(struct mtdev_state *state)
210 {
211 	struct input_event ev;
212 	while (!evbuf_empty(&state->inbuf)) {
213 		evbuf_get(&state->inbuf, &ev);
214 		evbuf_put(&state->outbuf, &ev);
215 	}
216 }
217 
218 /*
219  * filter_data - apply input filtering on new incoming data
220  * @state: mtdev state
221  * @dev: device capabilities
222  * @data: the incoming data to filter
223  * @prop: the properties to filter
224  * @slot: the slot the data refers to
225  */
filter_data(const struct mtdev_state * state,const struct mtdev * dev,struct mtdev_slot * data,bitmask_t prop,int slot)226 static void filter_data(const struct mtdev_state *state,
227 			const struct mtdev *dev,
228 			struct mtdev_slot *data, bitmask_t prop,
229 			int slot)
230 {
231 	int i;
232 	foreach_bit(i, prop) {
233 		int fuzz = mtdev_get_abs_fuzz(dev, mtdev_mt2abs(i));
234 		int oldval = get_sval(&state->data[slot], i);
235 		int value = get_sval(data, i);
236 		set_sval(data, i, defuzz(value, oldval, fuzz));
237 	}
238 }
239 
240 /*
241  * push_slot_changes - propagate state changes
242  * @state: mtdev state
243  * @data: the incoming data to propagate
244  * @prop: the properties to propagate
245  * @slot: the slot the data refers to
246  * @syn: reference to the SYN_REPORT event
247  */
push_slot_changes(struct mtdev_state * state,const struct mtdev_slot * data,bitmask_t prop,int slot,const struct input_event * syn)248 static void push_slot_changes(struct mtdev_state *state,
249 			      const struct mtdev_slot *data, bitmask_t prop,
250 			      int slot, const struct input_event *syn)
251 {
252 	struct input_event ev;
253 	int i, count = 0;
254 	foreach_bit(i, prop)
255 		if (get_sval(&state->data[slot], i) != get_sval(data, i))
256 			count++;
257 	if (!count)
258 		return;
259 	ev.input_event_sec = syn->input_event_sec;
260 	ev.input_event_usec = syn->input_event_usec;
261 	ev.type = EV_ABS;
262 	ev.code = ABS_MT_SLOT;
263 	ev.value = slot;
264 	if (state->slot != ev.value) {
265 		evbuf_put(&state->outbuf, &ev);
266 		state->slot = ev.value;
267 	}
268 	foreach_bit(i, prop) {
269 		ev.code = mtdev_mt2abs(i);
270 		ev.value = get_sval(data, i);
271 		if (get_sval(&state->data[slot], i) != ev.value) {
272 			evbuf_put(&state->outbuf, &ev);
273 			set_sval(&state->data[slot], i, ev.value);
274 		}
275 	}
276 }
277 
278 /*
279  * apply_typeA_changes - parse and propagate state changes
280  * @state: mtdev state
281  * @dev: device capabilities
282  * @data: array of data to apply
283  * @prop: array of properties to apply
284  * @size: number of contacts in array
285  * @syn: reference to the SYN_REPORT event
286  */
apply_typeA_changes(struct mtdev_state * state,const struct mtdev * dev,struct mtdev_slot * data,const bitmask_t * prop,int size,const struct input_event * syn)287 static void apply_typeA_changes(struct mtdev_state *state,
288 				const struct mtdev *dev,
289 				struct mtdev_slot *data, const bitmask_t *prop,
290 				int size, const struct input_event *syn)
291 {
292 	bitmask_t unused = ~state->used;
293 	bitmask_t used = 0;
294 	int i, slot, id;
295 	for (i = 0; i < size; i++) {
296 		id = data[i].tracking_id;
297 		foreach_bit(slot, state->used) {
298 			if (state->data[slot].tracking_id != id)
299 				continue;
300 			filter_data(state, dev, &data[i], prop[i], slot);
301 			push_slot_changes(state, &data[i], prop[i], slot, syn);
302 			SETBIT(used, slot);
303 			id = MT_ID_NULL;
304 			break;
305 		}
306 		if (id != MT_ID_NULL) {
307 			slot = firstbit(unused);
308 			push_slot_changes(state, &data[i], prop[i], slot, syn);
309 			SETBIT(used, slot);
310 			CLEARBIT(unused, slot);
311 		}
312 	}
313 
314 	/* clear unused slots and update slot usage */
315 	foreach_bit(slot, state->used & ~used) {
316 		struct mtdev_slot tdata = state->data[slot];
317 		bitmask_t tprop = BITMASK(mtdev_abs2mt(ABS_MT_TRACKING_ID));
318 		tdata.tracking_id = MT_ID_NULL;
319 		push_slot_changes(state, &tdata, tprop, slot, syn);
320 	}
321 	state->used = used;
322 }
323 
324 /*
325  * convert_A_to_B - propagate a type A packet as a type B packet
326  * @state: mtdev state
327  * @dev: device capabilities
328  * @syn: reference to the SYN_REPORT event
329  */
convert_A_to_B(struct mtdev_state * state,const struct mtdev * dev,const struct input_event * syn)330 static void convert_A_to_B(struct mtdev_state *state,
331 			   const struct mtdev *dev,
332 			   const struct input_event *syn)
333 {
334 	struct mtdev_slot data[DIM_FINGER];
335 	bitmask_t prop[DIM_FINGER];
336 	int size = process_typeA(state, data, prop);
337 	if (size < 0)
338 		return;
339 	if (!mtdev_has_mt_event(dev, ABS_MT_TRACKING_ID)) {
340 		bitmask_t touch = 0;
341 		int i;
342 		for (i = 0; i < size; i++)
343 			MODBIT(touch, i, istouch(&data[i], dev));
344 		assign_tracking_id(state, dev, data, prop, size, touch);
345 	}
346 	apply_typeA_changes(state, dev, data, prop, size, syn);
347 }
348 
mtdev_new(void)349 struct mtdev *mtdev_new(void)
350 {
351 	return calloc(1, sizeof(struct mtdev));
352 }
353 
mtdev_init(struct mtdev * dev)354 int mtdev_init(struct mtdev *dev)
355 {
356 	int i;
357 	memset(dev, 0, sizeof(struct mtdev));
358 	dev->state = calloc(1, sizeof(struct mtdev_state));
359 	if (!dev->state)
360 		return -ENOMEM;
361 	for (i = 0; i < DIM_FINGER; i++)
362 		dev->state->data[i].tracking_id = MT_ID_NULL;
363 	return 0;
364 }
365 
mtdev_open(struct mtdev * dev,int fd)366 int mtdev_open(struct mtdev *dev, int fd)
367 {
368 	int ret = -EINVAL;
369 
370 	if (!dev || fd < 0)
371 		goto error;
372 	ret = mtdev_init(dev);
373 	if (ret)
374 		goto error;
375 	ret = mtdev_configure(dev, fd);
376 	if (ret)
377 		goto error;
378 	return 0;
379 
380  error:
381 	mtdev_close(dev);
382 	return ret;
383 }
384 
mtdev_new_open(int fd)385 struct mtdev *mtdev_new_open(int fd)
386 {
387 	struct mtdev *dev;
388 
389 	dev = mtdev_new();
390 	if (!dev)
391 		return NULL;
392 	if (!mtdev_open(dev, fd))
393 		return dev;
394 
395 	mtdev_delete(dev);
396 	return NULL;
397 }
398 
mtdev_put_event(struct mtdev * dev,const struct input_event * ev)399 void mtdev_put_event(struct mtdev *dev, const struct input_event *ev)
400 {
401 	struct mtdev_state *state = dev->state;
402 	if (ev->type == EV_SYN && ev->code == SYN_REPORT) {
403 		bitmask_t head = state->outbuf.head;
404 		if (mtdev_has_mt_event(dev, ABS_MT_SLOT))
405 			process_typeB(state);
406 		else
407 			convert_A_to_B(state, dev, ev);
408 		if (state->outbuf.head != head)
409 			evbuf_put(&state->outbuf, ev);
410 	} else {
411 		evbuf_put(&state->inbuf, ev);
412 	}
413 }
414 
mtdev_close_delete(struct mtdev * dev)415 void mtdev_close_delete(struct mtdev *dev)
416 {
417 	mtdev_close(dev);
418 	mtdev_delete(dev);
419 }
420 
mtdev_close(struct mtdev * dev)421 void mtdev_close(struct mtdev *dev)
422 {
423 	if (dev) {
424 		free(dev->state);
425 		memset(dev, 0, sizeof(struct mtdev));
426 	}
427 }
428 
mtdev_delete(struct mtdev * dev)429 void mtdev_delete(struct mtdev *dev)
430 {
431 	free(dev);
432 }
433