Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * Input Multitouch Library
4 : : *
5 : : * Copyright (c) 2008-2010 Henrik Rydberg
6 : : */
7 : :
8 : : #include <linux/input/mt.h>
9 : : #include <linux/export.h>
10 : : #include <linux/slab.h>
11 : :
12 : : #define TRKID_SGN ((TRKID_MAX + 1) >> 1)
13 : :
14 : 0 : static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src)
15 : : {
16 [ # # # # ]: 0 : if (dev->absinfo && test_bit(src, dev->absbit)) {
17 : 0 : dev->absinfo[dst] = dev->absinfo[src];
18 : 0 : dev->absinfo[dst].fuzz = 0;
19 : 0 : dev->absbit[BIT_WORD(dst)] |= BIT_MASK(dst);
20 : : }
21 : 0 : }
22 : :
23 : : /**
24 : : * input_mt_init_slots() - initialize MT input slots
25 : : * @dev: input device supporting MT events and finger tracking
26 : : * @num_slots: number of slots used by the device
27 : : * @flags: mt tasks to handle in core
28 : : *
29 : : * This function allocates all necessary memory for MT slot handling
30 : : * in the input device, prepares the ABS_MT_SLOT and
31 : : * ABS_MT_TRACKING_ID events for use and sets up appropriate buffers.
32 : : * Depending on the flags set, it also performs pointer emulation and
33 : : * frame synchronization.
34 : : *
35 : : * May be called repeatedly. Returns -EINVAL if attempting to
36 : : * reinitialize with a different number of slots.
37 : : */
38 : 0 : int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
39 : : unsigned int flags)
40 : : {
41 : 0 : struct input_mt *mt = dev->mt;
42 : 0 : int i;
43 : :
44 [ # # ]: 0 : if (!num_slots)
45 : : return 0;
46 [ # # ]: 0 : if (mt)
47 [ # # ]: 0 : return mt->num_slots != num_slots ? -EINVAL : 0;
48 : :
49 [ # # ]: 0 : mt = kzalloc(struct_size(mt, slots, num_slots), GFP_KERNEL);
50 [ # # ]: 0 : if (!mt)
51 : 0 : goto err_mem;
52 : :
53 : 0 : mt->num_slots = num_slots;
54 : 0 : mt->flags = flags;
55 : 0 : input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
56 : 0 : input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
57 : :
58 [ # # ]: 0 : if (flags & (INPUT_MT_POINTER | INPUT_MT_DIRECT)) {
59 : 0 : __set_bit(EV_KEY, dev->evbit);
60 : 0 : __set_bit(BTN_TOUCH, dev->keybit);
61 : :
62 : 0 : copy_abs(dev, ABS_X, ABS_MT_POSITION_X);
63 : 0 : copy_abs(dev, ABS_Y, ABS_MT_POSITION_Y);
64 : 0 : copy_abs(dev, ABS_PRESSURE, ABS_MT_PRESSURE);
65 : : }
66 [ # # ]: 0 : if (flags & INPUT_MT_POINTER) {
67 : 0 : __set_bit(BTN_TOOL_FINGER, dev->keybit);
68 : 0 : __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
69 [ # # ]: 0 : if (num_slots >= 3)
70 : 0 : __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
71 [ # # ]: 0 : if (num_slots >= 4)
72 : 0 : __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
73 [ # # ]: 0 : if (num_slots >= 5)
74 : 0 : __set_bit(BTN_TOOL_QUINTTAP, dev->keybit);
75 : 0 : __set_bit(INPUT_PROP_POINTER, dev->propbit);
76 : : }
77 [ # # ]: 0 : if (flags & INPUT_MT_DIRECT)
78 : 0 : __set_bit(INPUT_PROP_DIRECT, dev->propbit);
79 [ # # ]: 0 : if (flags & INPUT_MT_SEMI_MT)
80 : 0 : __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
81 [ # # ]: 0 : if (flags & INPUT_MT_TRACK) {
82 : 0 : unsigned int n2 = num_slots * num_slots;
83 : 0 : mt->red = kcalloc(n2, sizeof(*mt->red), GFP_KERNEL);
84 [ # # ]: 0 : if (!mt->red)
85 : 0 : goto err_mem;
86 : : }
87 : :
88 : : /* Mark slots as 'inactive' */
89 [ # # ]: 0 : for (i = 0; i < num_slots; i++)
90 : 0 : input_mt_set_value(&mt->slots[i], ABS_MT_TRACKING_ID, -1);
91 : :
92 : : /* Mark slots as 'unused' */
93 : 0 : mt->frame = 1;
94 : :
95 : 0 : dev->mt = mt;
96 : 0 : return 0;
97 : 0 : err_mem:
98 : 0 : kfree(mt);
99 : 0 : return -ENOMEM;
100 : : }
101 : : EXPORT_SYMBOL(input_mt_init_slots);
102 : :
103 : : /**
104 : : * input_mt_destroy_slots() - frees the MT slots of the input device
105 : : * @dev: input device with allocated MT slots
106 : : *
107 : : * This function is only needed in error path as the input core will
108 : : * automatically free the MT slots when the device is destroyed.
109 : : */
110 : 78 : void input_mt_destroy_slots(struct input_dev *dev)
111 : : {
112 [ - + ]: 78 : if (dev->mt) {
113 : 0 : kfree(dev->mt->red);
114 : 0 : kfree(dev->mt);
115 : : }
116 : 78 : dev->mt = NULL;
117 : 78 : }
118 : : EXPORT_SYMBOL(input_mt_destroy_slots);
119 : :
120 : : /**
121 : : * input_mt_report_slot_state() - report contact state
122 : : * @dev: input device with allocated MT slots
123 : : * @tool_type: the tool type to use in this slot
124 : : * @active: true if contact is active, false otherwise
125 : : *
126 : : * Reports a contact via ABS_MT_TRACKING_ID, and optionally
127 : : * ABS_MT_TOOL_TYPE. If active is true and the slot is currently
128 : : * inactive, or if the tool type is changed, a new tracking id is
129 : : * assigned to the slot. The tool type is only reported if the
130 : : * corresponding absbit field is set.
131 : : *
132 : : * Returns true if contact is active.
133 : : */
134 : 0 : bool input_mt_report_slot_state(struct input_dev *dev,
135 : : unsigned int tool_type, bool active)
136 : : {
137 : 0 : struct input_mt *mt = dev->mt;
138 : 0 : struct input_mt_slot *slot;
139 : 0 : int id;
140 : :
141 [ # # ]: 0 : if (!mt)
142 : : return false;
143 : :
144 : 0 : slot = &mt->slots[mt->slot];
145 : 0 : slot->frame = mt->frame;
146 : :
147 [ # # ]: 0 : if (!active) {
148 : 0 : input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
149 : 0 : return false;
150 : : }
151 : :
152 [ # # ]: 0 : id = input_mt_get_value(slot, ABS_MT_TRACKING_ID);
153 [ # # ]: 0 : if (id < 0)
154 : 0 : id = input_mt_new_trkid(mt);
155 : :
156 : 0 : input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
157 : 0 : input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);
158 : :
159 : 0 : return true;
160 : : }
161 : : EXPORT_SYMBOL(input_mt_report_slot_state);
162 : :
163 : : /**
164 : : * input_mt_report_finger_count() - report contact count
165 : : * @dev: input device with allocated MT slots
166 : : * @count: the number of contacts
167 : : *
168 : : * Reports the contact count via BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP,
169 : : * BTN_TOOL_TRIPLETAP and BTN_TOOL_QUADTAP.
170 : : *
171 : : * The input core ensures only the KEY events already setup for
172 : : * this device will produce output.
173 : : */
174 : 0 : void input_mt_report_finger_count(struct input_dev *dev, int count)
175 : : {
176 : 0 : input_event(dev, EV_KEY, BTN_TOOL_FINGER, count == 1);
177 : 0 : input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2);
178 : 0 : input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3);
179 : 0 : input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count == 4);
180 : 0 : input_event(dev, EV_KEY, BTN_TOOL_QUINTTAP, count == 5);
181 : 0 : }
182 : : EXPORT_SYMBOL(input_mt_report_finger_count);
183 : :
184 : : /**
185 : : * input_mt_report_pointer_emulation() - common pointer emulation
186 : : * @dev: input device with allocated MT slots
187 : : * @use_count: report number of active contacts as finger count
188 : : *
189 : : * Performs legacy pointer emulation via BTN_TOUCH, ABS_X, ABS_Y and
190 : : * ABS_PRESSURE. Touchpad finger count is emulated if use_count is true.
191 : : *
192 : : * The input core ensures only the KEY and ABS axes already setup for
193 : : * this device will produce output.
194 : : */
195 : 0 : void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
196 : : {
197 : 0 : struct input_mt *mt = dev->mt;
198 : 0 : struct input_mt_slot *oldest;
199 : 0 : int oldid, count, i;
200 : :
201 [ # # ]: 0 : if (!mt)
202 : : return;
203 : :
204 : 0 : oldest = NULL;
205 : 0 : oldid = mt->trkid;
206 : 0 : count = 0;
207 : :
208 [ # # ]: 0 : for (i = 0; i < mt->num_slots; ++i) {
209 : 0 : struct input_mt_slot *ps = &mt->slots[i];
210 [ # # ]: 0 : int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
211 : :
212 [ # # ]: 0 : if (id < 0)
213 : 0 : continue;
214 [ # # ]: 0 : if ((id - oldid) & TRKID_SGN) {
215 : 0 : oldest = ps;
216 : 0 : oldid = id;
217 : : }
218 : 0 : count++;
219 : : }
220 : :
221 : 0 : input_event(dev, EV_KEY, BTN_TOUCH, count > 0);
222 : :
223 [ # # ]: 0 : if (use_count) {
224 [ # # # # ]: 0 : if (count == 0 &&
225 [ # # ]: 0 : !test_bit(ABS_MT_DISTANCE, dev->absbit) &&
226 [ # # ]: 0 : test_bit(ABS_DISTANCE, dev->absbit) &&
227 [ # # ]: 0 : input_abs_get_val(dev, ABS_DISTANCE) != 0) {
228 : : /*
229 : : * Force reporting BTN_TOOL_FINGER for devices that
230 : : * only report general hover (and not per-contact
231 : : * distance) when contact is in proximity but not
232 : : * on the surface.
233 : : */
234 : 0 : count = 1;
235 : : }
236 : :
237 : 0 : input_mt_report_finger_count(dev, count);
238 : : }
239 : :
240 [ # # ]: 0 : if (oldest) {
241 : 0 : int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
242 : 0 : int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);
243 : :
244 : 0 : input_event(dev, EV_ABS, ABS_X, x);
245 : 0 : input_event(dev, EV_ABS, ABS_Y, y);
246 : :
247 [ # # ]: 0 : if (test_bit(ABS_MT_PRESSURE, dev->absbit)) {
248 : 0 : int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
249 : 0 : input_event(dev, EV_ABS, ABS_PRESSURE, p);
250 : : }
251 : : } else {
252 [ # # ]: 0 : if (test_bit(ABS_MT_PRESSURE, dev->absbit))
253 : 0 : input_event(dev, EV_ABS, ABS_PRESSURE, 0);
254 : : }
255 : : }
256 : : EXPORT_SYMBOL(input_mt_report_pointer_emulation);
257 : :
258 : 0 : static void __input_mt_drop_unused(struct input_dev *dev, struct input_mt *mt)
259 : : {
260 : 0 : int i;
261 : :
262 [ # # ]: 0 : for (i = 0; i < mt->num_slots; i++) {
263 [ # # ]: 0 : if (!input_mt_is_used(mt, &mt->slots[i])) {
264 : 0 : input_mt_slot(dev, i);
265 : 0 : input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
266 : : }
267 : : }
268 : 0 : }
269 : :
270 : : /**
271 : : * input_mt_drop_unused() - Inactivate slots not seen in this frame
272 : : * @dev: input device with allocated MT slots
273 : : *
274 : : * Lift all slots not seen since the last call to this function.
275 : : */
276 : 0 : void input_mt_drop_unused(struct input_dev *dev)
277 : : {
278 : 0 : struct input_mt *mt = dev->mt;
279 : :
280 [ # # ]: 0 : if (mt) {
281 : 0 : __input_mt_drop_unused(dev, mt);
282 : 0 : mt->frame++;
283 : : }
284 : 0 : }
285 : : EXPORT_SYMBOL(input_mt_drop_unused);
286 : :
287 : : /**
288 : : * input_mt_sync_frame() - synchronize mt frame
289 : : * @dev: input device with allocated MT slots
290 : : *
291 : : * Close the frame and prepare the internal state for a new one.
292 : : * Depending on the flags, marks unused slots as inactive and performs
293 : : * pointer emulation.
294 : : */
295 : 0 : void input_mt_sync_frame(struct input_dev *dev)
296 : : {
297 : 0 : struct input_mt *mt = dev->mt;
298 : 0 : bool use_count = false;
299 : :
300 [ # # ]: 0 : if (!mt)
301 : : return;
302 : :
303 [ # # ]: 0 : if (mt->flags & INPUT_MT_DROP_UNUSED)
304 : 0 : __input_mt_drop_unused(dev, mt);
305 : :
306 [ # # ]: 0 : if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT))
307 : 0 : use_count = true;
308 : :
309 : 0 : input_mt_report_pointer_emulation(dev, use_count);
310 : :
311 : 0 : mt->frame++;
312 : : }
313 : : EXPORT_SYMBOL(input_mt_sync_frame);
314 : :
315 : 0 : static int adjust_dual(int *begin, int step, int *end, int eq, int mu)
316 : : {
317 : 0 : int f, *p, s, c;
318 : :
319 [ # # ]: 0 : if (begin == end)
320 : : return 0;
321 : :
322 : 0 : f = *begin;
323 : 0 : p = begin + step;
324 [ # # ]: 0 : s = p == end ? f + 1 : *p;
325 : :
326 [ # # ]: 0 : for (; p != end; p += step)
327 [ # # ]: 0 : if (*p < f)
328 : : s = f, f = *p;
329 : 0 : else if (*p < s)
330 : : s = *p;
331 : :
332 : 0 : c = (f + s + 1) / 2;
333 [ # # # # : 0 : if (c == 0 || (c > mu && (!eq || mu > 0)))
# # ]
334 : : return 0;
335 : : /* Improve convergence for positive matrices by penalizing overcovers */
336 [ # # ]: 0 : if (s < 0 && mu <= 0)
337 : 0 : c *= 2;
338 : :
339 [ # # ]: 0 : for (p = begin; p != end; p += step)
340 : 0 : *p -= c;
341 : :
342 [ # # # # ]: 0 : return (c < s && s <= 0) || (f >= 0 && f < c);
343 : : }
344 : :
345 : 0 : static void find_reduced_matrix(int *w, int nr, int nc, int nrc, int mu)
346 : : {
347 : 0 : int i, k, sum;
348 : :
349 [ # # ]: 0 : for (k = 0; k < nrc; k++) {
350 [ # # ]: 0 : for (i = 0; i < nr; i++)
351 : 0 : adjust_dual(w + i, nr, w + i + nrc, nr <= nc, mu);
352 : : sum = 0;
353 [ # # ]: 0 : for (i = 0; i < nrc; i += nr)
354 : 0 : sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr, mu);
355 [ # # ]: 0 : if (!sum)
356 : : break;
357 : : }
358 : 0 : }
359 : :
360 : 0 : static int input_mt_set_matrix(struct input_mt *mt,
361 : : const struct input_mt_pos *pos, int num_pos,
362 : : int mu)
363 : : {
364 : 0 : const struct input_mt_pos *p;
365 : 0 : struct input_mt_slot *s;
366 : 0 : int *w = mt->red;
367 : 0 : int x, y;
368 : :
369 [ # # ]: 0 : for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
370 [ # # ]: 0 : if (!input_mt_is_active(s))
371 : 0 : continue;
372 : 0 : x = input_mt_get_value(s, ABS_MT_POSITION_X);
373 : 0 : y = input_mt_get_value(s, ABS_MT_POSITION_Y);
374 [ # # ]: 0 : for (p = pos; p != pos + num_pos; p++) {
375 : 0 : int dx = x - p->x, dy = y - p->y;
376 : 0 : *w++ = dx * dx + dy * dy - mu;
377 : : }
378 : : }
379 : :
380 : 0 : return w - mt->red;
381 : : }
382 : :
383 : 0 : static void input_mt_set_slots(struct input_mt *mt,
384 : : int *slots, int num_pos)
385 : : {
386 : 0 : struct input_mt_slot *s;
387 : 0 : int *w = mt->red, j;
388 : :
389 [ # # ]: 0 : for (j = 0; j != num_pos; j++)
390 : 0 : slots[j] = -1;
391 : :
392 [ # # ]: 0 : for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
393 [ # # ]: 0 : if (!input_mt_is_active(s))
394 : 0 : continue;
395 : :
396 [ # # ]: 0 : for (j = 0; j != num_pos; j++) {
397 [ # # ]: 0 : if (w[j] < 0) {
398 : 0 : slots[j] = s - mt->slots;
399 : 0 : break;
400 : : }
401 : : }
402 : :
403 : 0 : w += num_pos;
404 : : }
405 : :
406 [ # # ]: 0 : for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
407 [ # # ]: 0 : if (input_mt_is_active(s))
408 : 0 : continue;
409 : :
410 [ # # ]: 0 : for (j = 0; j != num_pos; j++) {
411 [ # # ]: 0 : if (slots[j] < 0) {
412 : 0 : slots[j] = s - mt->slots;
413 : 0 : break;
414 : : }
415 : : }
416 : : }
417 : 0 : }
418 : :
419 : : /**
420 : : * input_mt_assign_slots() - perform a best-match assignment
421 : : * @dev: input device with allocated MT slots
422 : : * @slots: the slot assignment to be filled
423 : : * @pos: the position array to match
424 : : * @num_pos: number of positions
425 : : * @dmax: maximum ABS_MT_POSITION displacement (zero for infinite)
426 : : *
427 : : * Performs a best match against the current contacts and returns
428 : : * the slot assignment list. New contacts are assigned to unused
429 : : * slots.
430 : : *
431 : : * The assignments are balanced so that all coordinate displacements are
432 : : * below the euclidian distance dmax. If no such assignment can be found,
433 : : * some contacts are assigned to unused slots.
434 : : *
435 : : * Returns zero on success, or negative error in case of failure.
436 : : */
437 : 0 : int input_mt_assign_slots(struct input_dev *dev, int *slots,
438 : : const struct input_mt_pos *pos, int num_pos,
439 : : int dmax)
440 : : {
441 : 0 : struct input_mt *mt = dev->mt;
442 : 0 : int mu = 2 * dmax * dmax;
443 : 0 : int nrc;
444 : :
445 [ # # # # ]: 0 : if (!mt || !mt->red)
446 : : return -ENXIO;
447 [ # # ]: 0 : if (num_pos > mt->num_slots)
448 : : return -EINVAL;
449 [ # # ]: 0 : if (num_pos < 1)
450 : : return 0;
451 : :
452 : 0 : nrc = input_mt_set_matrix(mt, pos, num_pos, mu);
453 : 0 : find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc, mu);
454 : 0 : input_mt_set_slots(mt, slots, num_pos);
455 : :
456 : 0 : return 0;
457 : : }
458 : : EXPORT_SYMBOL(input_mt_assign_slots);
459 : :
460 : : /**
461 : : * input_mt_get_slot_by_key() - return slot matching key
462 : : * @dev: input device with allocated MT slots
463 : : * @key: the key of the sought slot
464 : : *
465 : : * Returns the slot of the given key, if it exists, otherwise
466 : : * set the key on the first unused slot and return.
467 : : *
468 : : * If no available slot can be found, -1 is returned.
469 : : * Note that for this function to work properly, input_mt_sync_frame() has
470 : : * to be called at each frame.
471 : : */
472 : 0 : int input_mt_get_slot_by_key(struct input_dev *dev, int key)
473 : : {
474 : 0 : struct input_mt *mt = dev->mt;
475 : 0 : struct input_mt_slot *s;
476 : :
477 [ # # ]: 0 : if (!mt)
478 : : return -1;
479 : :
480 [ # # ]: 0 : for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
481 [ # # # # ]: 0 : if (input_mt_is_active(s) && s->key == key)
482 : 0 : return s - mt->slots;
483 : :
484 [ # # ]: 0 : for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
485 [ # # # # ]: 0 : if (!input_mt_is_active(s) && !input_mt_is_used(mt, s)) {
486 : 0 : s->key = key;
487 : 0 : return s - mt->slots;
488 : : }
489 : :
490 : : return -1;
491 : : }
492 : : EXPORT_SYMBOL(input_mt_get_slot_by_key);
|