12b3f6d66SOleksandr Tymoshenko /*-
24174302bSVladimir Kondratyev * Copyright (c) 2016, 2020 Vladimir Kondratyev <[email protected]>
32b3f6d66SOleksandr Tymoshenko * All rights reserved.
42b3f6d66SOleksandr Tymoshenko *
52b3f6d66SOleksandr Tymoshenko * Redistribution and use in source and binary forms, with or without
62b3f6d66SOleksandr Tymoshenko * modification, are permitted provided that the following conditions
72b3f6d66SOleksandr Tymoshenko * are met:
82b3f6d66SOleksandr Tymoshenko * 1. Redistributions of source code must retain the above copyright
92b3f6d66SOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer.
102b3f6d66SOleksandr Tymoshenko * 2. Redistributions in binary form must reproduce the above copyright
112b3f6d66SOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer in the
122b3f6d66SOleksandr Tymoshenko * documentation and/or other materials provided with the distribution.
132b3f6d66SOleksandr Tymoshenko *
142b3f6d66SOleksandr Tymoshenko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
152b3f6d66SOleksandr Tymoshenko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
162b3f6d66SOleksandr Tymoshenko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172b3f6d66SOleksandr Tymoshenko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
182b3f6d66SOleksandr Tymoshenko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
192b3f6d66SOleksandr Tymoshenko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
202b3f6d66SOleksandr Tymoshenko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
212b3f6d66SOleksandr Tymoshenko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
222b3f6d66SOleksandr Tymoshenko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232b3f6d66SOleksandr Tymoshenko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242b3f6d66SOleksandr Tymoshenko * SUCH DAMAGE.
252b3f6d66SOleksandr Tymoshenko *
262b3f6d66SOleksandr Tymoshenko * $FreeBSD$
272b3f6d66SOleksandr Tymoshenko */
28b79de251SVladimir Kondratyev /*-
29b79de251SVladimir Kondratyev * Copyright (c) 2015, 2016 Ulf Brosziewski
30b79de251SVladimir Kondratyev *
31b79de251SVladimir Kondratyev * Permission to use, copy, modify, and distribute this software for any
32b79de251SVladimir Kondratyev * purpose with or without fee is hereby granted, provided that the above
33b79de251SVladimir Kondratyev * copyright notice and this permission notice appear in all copies.
34b79de251SVladimir Kondratyev *
35b79de251SVladimir Kondratyev * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
36b79de251SVladimir Kondratyev * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
37b79de251SVladimir Kondratyev * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
38b79de251SVladimir Kondratyev * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
39b79de251SVladimir Kondratyev * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
40b79de251SVladimir Kondratyev * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
41b79de251SVladimir Kondratyev * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
42b79de251SVladimir Kondratyev */
432b3f6d66SOleksandr Tymoshenko
442b3f6d66SOleksandr Tymoshenko #include <sys/param.h>
452b3f6d66SOleksandr Tymoshenko #include <sys/lock.h>
46ea2e26b1SVladimir Kondratyev #include <sys/malloc.h>
472b3f6d66SOleksandr Tymoshenko #include <sys/mutex.h>
482b3f6d66SOleksandr Tymoshenko #include <sys/systm.h>
492b3f6d66SOleksandr Tymoshenko
502b3f6d66SOleksandr Tymoshenko #include <dev/evdev/evdev.h>
512b3f6d66SOleksandr Tymoshenko #include <dev/evdev/evdev_private.h>
52ea2e26b1SVladimir Kondratyev #include <dev/evdev/input.h>
532b3f6d66SOleksandr Tymoshenko
542b3f6d66SOleksandr Tymoshenko #ifdef DEBUG
552b3f6d66SOleksandr Tymoshenko #define debugf(fmt, args...) printf("evdev: " fmt "\n", ##args)
562b3f6d66SOleksandr Tymoshenko #else
572b3f6d66SOleksandr Tymoshenko #define debugf(fmt, args...)
582b3f6d66SOleksandr Tymoshenko #endif
592b3f6d66SOleksandr Tymoshenko
605bf6cf0fSVladimir Kondratyev typedef u_int slotset_t;
615bf6cf0fSVladimir Kondratyev
625bf6cf0fSVladimir Kondratyev _Static_assert(MAX_MT_SLOTS < sizeof(slotset_t) * 8, "MAX_MT_SLOTS too big");
635bf6cf0fSVladimir Kondratyev
645bf6cf0fSVladimir Kondratyev #define FOREACHBIT(v, i) \
655bf6cf0fSVladimir Kondratyev for ((i) = ffs(v) - 1; (i) != -1; (i) = ffs((v) & (~1 << (i))) - 1)
665bf6cf0fSVladimir Kondratyev
67de6d60eeSVladimir Kondratyev struct {
68de6d60eeSVladimir Kondratyev uint16_t mt;
69de6d60eeSVladimir Kondratyev uint16_t st;
70de6d60eeSVladimir Kondratyev int32_t max;
71de6d60eeSVladimir Kondratyev } static evdev_mtstmap[] = {
72de6d60eeSVladimir Kondratyev { ABS_MT_POSITION_X, ABS_X, 0 },
73de6d60eeSVladimir Kondratyev { ABS_MT_POSITION_Y, ABS_Y, 0 },
74de6d60eeSVladimir Kondratyev { ABS_MT_PRESSURE, ABS_PRESSURE, 255 },
75de6d60eeSVladimir Kondratyev { ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH, 15 },
762b3f6d66SOleksandr Tymoshenko };
772b3f6d66SOleksandr Tymoshenko
782b3f6d66SOleksandr Tymoshenko struct evdev_mt {
79a437dfa5SVladimir Kondratyev int last_reported_slot;
80f160aa0dSVladimir Kondratyev uint16_t tracking_id;
81f160aa0dSVladimir Kondratyev int32_t tracking_ids[MAX_MT_SLOTS];
8245fd5fe9SVladimir Kondratyev bool type_a;
83de6d60eeSVladimir Kondratyev u_int mtst_events;
845bf6cf0fSVladimir Kondratyev /* the set of slots with active touches */
855bf6cf0fSVladimir Kondratyev slotset_t touches;
865bf6cf0fSVladimir Kondratyev /* the set of slots with unsynchronized state */
875bf6cf0fSVladimir Kondratyev slotset_t frame;
884174302bSVladimir Kondratyev /* the set of slots to match with active touches */
894174302bSVladimir Kondratyev slotset_t match_frame;
904174302bSVladimir Kondratyev int match_slot;
914174302bSVladimir Kondratyev union evdev_mt_slot *match_slots;
92b79de251SVladimir Kondratyev int *matrix;
93759a5cd1SVladimir Kondratyev union evdev_mt_slot slots[];
942b3f6d66SOleksandr Tymoshenko };
952b3f6d66SOleksandr Tymoshenko
96a437dfa5SVladimir Kondratyev static void evdev_mt_send_st_compat(struct evdev_dev *);
97a437dfa5SVladimir Kondratyev static void evdev_mt_send_autorel(struct evdev_dev *);
984174302bSVladimir Kondratyev static void evdev_mt_replay_events(struct evdev_dev *);
99a437dfa5SVladimir Kondratyev
1005bf6cf0fSVladimir Kondratyev static inline int
ffc_slot(struct evdev_dev * evdev,slotset_t slots)1015bf6cf0fSVladimir Kondratyev ffc_slot(struct evdev_dev *evdev, slotset_t slots)
1025bf6cf0fSVladimir Kondratyev {
103*1097f2f4SJohn Baldwin return (ffs(~slots & ((2U << MAXIMAL_MT_SLOT(evdev)) - 1)) - 1);
1045bf6cf0fSVladimir Kondratyev }
1055bf6cf0fSVladimir Kondratyev
1062b3f6d66SOleksandr Tymoshenko void
evdev_mt_init(struct evdev_dev * evdev)1072b3f6d66SOleksandr Tymoshenko evdev_mt_init(struct evdev_dev *evdev)
1082b3f6d66SOleksandr Tymoshenko {
109b79de251SVladimir Kondratyev struct evdev_mt *mt;
110b79de251SVladimir Kondratyev size_t size = offsetof(struct evdev_mt, slots);
111a437dfa5SVladimir Kondratyev int slot, slots;
11245fd5fe9SVladimir Kondratyev bool type_a;
11345fd5fe9SVladimir Kondratyev
11445fd5fe9SVladimir Kondratyev type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT);
11545fd5fe9SVladimir Kondratyev if (type_a) {
11645fd5fe9SVladimir Kondratyev /* Add events produced by MT type A to type B converter */
11745fd5fe9SVladimir Kondratyev evdev_support_abs(evdev,
11845fd5fe9SVladimir Kondratyev ABS_MT_SLOT, 0, MAX_MT_SLOTS - 1, 0, 0, 0);
11945fd5fe9SVladimir Kondratyev evdev_support_abs(evdev,
12045fd5fe9SVladimir Kondratyev ABS_MT_TRACKING_ID, -1, MAX_MT_SLOTS - 1, 0, 0, 0);
12145fd5fe9SVladimir Kondratyev }
1222b3f6d66SOleksandr Tymoshenko
1232b3f6d66SOleksandr Tymoshenko slots = MAXIMAL_MT_SLOT(evdev) + 1;
124b79de251SVladimir Kondratyev size += sizeof(mt->slots[0]) * slots;
125b79de251SVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) {
1264174302bSVladimir Kondratyev size += sizeof(mt->match_slots[0]) * slots;
127b79de251SVladimir Kondratyev size += sizeof(mt->matrix[0]) * (slots + 6) * slots;
128b79de251SVladimir Kondratyev }
1292b3f6d66SOleksandr Tymoshenko
130b79de251SVladimir Kondratyev mt = malloc(size, M_EVDEV, M_WAITOK | M_ZERO);
131b79de251SVladimir Kondratyev evdev->ev_mt = mt;
13245fd5fe9SVladimir Kondratyev mt->type_a = type_a;
133b79de251SVladimir Kondratyev
134b79de251SVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) {
1354174302bSVladimir Kondratyev mt->match_slots = mt->slots + slots;
1364174302bSVladimir Kondratyev mt->matrix = (int *)(mt->match_slots + slots);
137b79de251SVladimir Kondratyev }
1382b3f6d66SOleksandr Tymoshenko
1392b3f6d66SOleksandr Tymoshenko /* Initialize multitouch protocol type B states */
1405bf6cf0fSVladimir Kondratyev for (slot = 0; slot < slots; slot++)
1414174302bSVladimir Kondratyev mt->slots[slot].id = -1;
1422b3f6d66SOleksandr Tymoshenko
143f160aa0dSVladimir Kondratyev if (!bit_test(evdev->ev_flags, EVDEV_FLAG_MT_KEEPID))
144f160aa0dSVladimir Kondratyev evdev_support_abs(evdev,
145f160aa0dSVladimir Kondratyev ABS_MT_TRACKING_ID, -1, UINT16_MAX, 0, 0, 0);
1462b3f6d66SOleksandr Tymoshenko if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
1472b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(evdev);
1482b3f6d66SOleksandr Tymoshenko }
1492b3f6d66SOleksandr Tymoshenko
1502b3f6d66SOleksandr Tymoshenko void
evdev_mt_free(struct evdev_dev * evdev)1512b3f6d66SOleksandr Tymoshenko evdev_mt_free(struct evdev_dev *evdev)
1522b3f6d66SOleksandr Tymoshenko {
1532b3f6d66SOleksandr Tymoshenko free(evdev->ev_mt, M_EVDEV);
1542b3f6d66SOleksandr Tymoshenko }
1552b3f6d66SOleksandr Tymoshenko
156a437dfa5SVladimir Kondratyev void
evdev_mt_sync_frame(struct evdev_dev * evdev)157a437dfa5SVladimir Kondratyev evdev_mt_sync_frame(struct evdev_dev *evdev)
1582b3f6d66SOleksandr Tymoshenko {
1594174302bSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK))
1604174302bSVladimir Kondratyev evdev_mt_replay_events(evdev);
161a437dfa5SVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL))
162a437dfa5SVladimir Kondratyev evdev_mt_send_autorel(evdev);
163a437dfa5SVladimir Kondratyev if (evdev->ev_report_opened &&
164a437dfa5SVladimir Kondratyev bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
165a437dfa5SVladimir Kondratyev evdev_mt_send_st_compat(evdev);
1665bf6cf0fSVladimir Kondratyev evdev->ev_mt->frame = 0;
167a437dfa5SVladimir Kondratyev }
1682b3f6d66SOleksandr Tymoshenko
169759a5cd1SVladimir Kondratyev static void
evdev_mt_send_slot(struct evdev_dev * evdev,int slot,union evdev_mt_slot * state)170759a5cd1SVladimir Kondratyev evdev_mt_send_slot(struct evdev_dev *evdev, int slot,
171759a5cd1SVladimir Kondratyev union evdev_mt_slot *state)
172759a5cd1SVladimir Kondratyev {
173759a5cd1SVladimir Kondratyev int i;
174759a5cd1SVladimir Kondratyev bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT);
175759a5cd1SVladimir Kondratyev
176759a5cd1SVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev);
177759a5cd1SVladimir Kondratyev MPASS(type_a || (slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)));
178759a5cd1SVladimir Kondratyev MPASS(!type_a || state != NULL);
179759a5cd1SVladimir Kondratyev
180759a5cd1SVladimir Kondratyev if (!type_a) {
181759a5cd1SVladimir Kondratyev evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot);
182759a5cd1SVladimir Kondratyev if (state == NULL) {
183759a5cd1SVladimir Kondratyev evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID, -1);
184759a5cd1SVladimir Kondratyev return;
185759a5cd1SVladimir Kondratyev }
186759a5cd1SVladimir Kondratyev }
187759a5cd1SVladimir Kondratyev bit_foreach_at(evdev->ev_abs_flags, ABS_MT_FIRST, ABS_MT_LAST + 1, i)
188759a5cd1SVladimir Kondratyev evdev_send_event(evdev, EV_ABS, i,
189759a5cd1SVladimir Kondratyev state->val[ABS_MT_INDEX(i)]);
190759a5cd1SVladimir Kondratyev if (type_a)
191759a5cd1SVladimir Kondratyev evdev_send_event(evdev, EV_SYN, SYN_MT_REPORT, 1);
192759a5cd1SVladimir Kondratyev }
193759a5cd1SVladimir Kondratyev
194759a5cd1SVladimir Kondratyev int
evdev_mt_push_slot(struct evdev_dev * evdev,int slot,union evdev_mt_slot * state)195759a5cd1SVladimir Kondratyev evdev_mt_push_slot(struct evdev_dev *evdev, int slot,
196759a5cd1SVladimir Kondratyev union evdev_mt_slot *state)
197759a5cd1SVladimir Kondratyev {
1984174302bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
199759a5cd1SVladimir Kondratyev bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT);
200759a5cd1SVladimir Kondratyev
20145fd5fe9SVladimir Kondratyev if ((type_a || (mt != NULL && mt->type_a)) && state == NULL)
202759a5cd1SVladimir Kondratyev return (EINVAL);
203759a5cd1SVladimir Kondratyev if (!type_a && (slot < 0 || slot > MAXIMAL_MT_SLOT(evdev)))
204759a5cd1SVladimir Kondratyev return (EINVAL);
205759a5cd1SVladimir Kondratyev
206759a5cd1SVladimir Kondratyev EVDEV_ENTER(evdev);
20745fd5fe9SVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK) && mt->type_a) {
20845fd5fe9SVladimir Kondratyev mt->match_slots[mt->match_slot] = *state;
20945fd5fe9SVladimir Kondratyev evdev_mt_record_event(evdev, EV_SYN, SYN_MT_REPORT, 1);
21045fd5fe9SVladimir Kondratyev } else if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) {
2114174302bSVladimir Kondratyev evdev_mt_record_event(evdev, EV_ABS, ABS_MT_SLOT, slot);
2124174302bSVladimir Kondratyev if (state != NULL)
2134174302bSVladimir Kondratyev mt->match_slots[mt->match_slot] = *state;
2144174302bSVladimir Kondratyev else
2154174302bSVladimir Kondratyev evdev_mt_record_event(evdev, EV_ABS,
2164174302bSVladimir Kondratyev ABS_MT_TRACKING_ID, -1);
2174174302bSVladimir Kondratyev } else
218759a5cd1SVladimir Kondratyev evdev_mt_send_slot(evdev, slot, state);
219759a5cd1SVladimir Kondratyev EVDEV_EXIT(evdev);
220759a5cd1SVladimir Kondratyev
221759a5cd1SVladimir Kondratyev return (0);
222759a5cd1SVladimir Kondratyev }
223759a5cd1SVladimir Kondratyev
224b79de251SVladimir Kondratyev /*
225b79de251SVladimir Kondratyev * Find a minimum-weight matching for an m-by-n matrix.
226b79de251SVladimir Kondratyev *
227b79de251SVladimir Kondratyev * m must be greater than or equal to n. The size of the buffer must be
228b79de251SVladimir Kondratyev * at least 3m + 3n.
229b79de251SVladimir Kondratyev *
230b79de251SVladimir Kondratyev * On return, the first m elements of the buffer contain the row-to-
231b79de251SVladimir Kondratyev * column mappings, i.e., buffer[i] is the column index for row i, or -1
232b79de251SVladimir Kondratyev * if there is no assignment for that row (which may happen if n < m).
233b79de251SVladimir Kondratyev *
234b79de251SVladimir Kondratyev * Wrong results because of overflows will not occur with input values
235b79de251SVladimir Kondratyev * in the range of 0 to INT_MAX / 2 inclusive.
236b79de251SVladimir Kondratyev *
237b79de251SVladimir Kondratyev * The function applies the Dinic-Kronrod algorithm. It is not modern or
238b79de251SVladimir Kondratyev * popular, but it seems to be a good choice for small matrices at least.
239b79de251SVladimir Kondratyev * The original form of the algorithm is modified as follows: There is no
240b79de251SVladimir Kondratyev * initial search for row minima, the initial assignments are in a
241b79de251SVladimir Kondratyev * "virtual" column with the index -1 and zero values. This permits inputs
242b79de251SVladimir Kondratyev * with n < m, and it simplifies the reassignments.
243b79de251SVladimir Kondratyev */
244b79de251SVladimir Kondratyev static void
evdev_mt_matching(int * matrix,int m,int n,int * buffer)245b79de251SVladimir Kondratyev evdev_mt_matching(int *matrix, int m, int n, int *buffer)
246b79de251SVladimir Kondratyev {
247b79de251SVladimir Kondratyev int i, j, k, d, e, row, col, delta;
248b79de251SVladimir Kondratyev int *p;
249b79de251SVladimir Kondratyev int *r2c = buffer; /* row-to-column assignments */
250b79de251SVladimir Kondratyev int *red = r2c + m; /* reduced values of the assignments */
251b79de251SVladimir Kondratyev int *mc = red + m; /* row-wise minimal elements of cs */
252b79de251SVladimir Kondratyev int *cs = mc + m; /* the column set */
253b79de251SVladimir Kondratyev int *c2r = cs + n; /* column-to-row assignments in cs */
254b79de251SVladimir Kondratyev int *cd = c2r + n; /* column deltas (reduction) */
255b79de251SVladimir Kondratyev
256b79de251SVladimir Kondratyev for (p = r2c; p < red; *p++ = -1) {}
257b79de251SVladimir Kondratyev for (; p < mc; *p++ = 0) {}
258b79de251SVladimir Kondratyev for (col = 0; col < n; col++) {
259b79de251SVladimir Kondratyev delta = INT_MAX;
260b79de251SVladimir Kondratyev for (i = 0, p = matrix + col; i < m; i++, p += n) {
261b79de251SVladimir Kondratyev d = *p - red[i];
262b79de251SVladimir Kondratyev if (d < delta || (d == delta && r2c[i] < 0)) {
263b79de251SVladimir Kondratyev delta = d;
264b79de251SVladimir Kondratyev row = i;
265b79de251SVladimir Kondratyev }
266b79de251SVladimir Kondratyev }
267b79de251SVladimir Kondratyev cd[col] = delta;
268b79de251SVladimir Kondratyev if (r2c[row] < 0) {
269b79de251SVladimir Kondratyev r2c[row] = col;
270b79de251SVladimir Kondratyev continue;
271b79de251SVladimir Kondratyev }
272b79de251SVladimir Kondratyev for (p = mc; p < cs; *p++ = col) {}
273b79de251SVladimir Kondratyev for (k = 0; (j = r2c[row]) >= 0;) {
274b79de251SVladimir Kondratyev cs[k++] = j;
275b79de251SVladimir Kondratyev c2r[j] = row;
276b79de251SVladimir Kondratyev mc[row] -= n;
277b79de251SVladimir Kondratyev delta = INT_MAX;
278b79de251SVladimir Kondratyev for (i = 0, p = matrix; i < m; i++, p += n)
279b79de251SVladimir Kondratyev if (mc[i] >= 0) {
280b79de251SVladimir Kondratyev d = p[mc[i]] - cd[mc[i]];
281b79de251SVladimir Kondratyev e = p[j] - cd[j];
282b79de251SVladimir Kondratyev if (e < d) {
283b79de251SVladimir Kondratyev d = e;
284b79de251SVladimir Kondratyev mc[i] = j;
285b79de251SVladimir Kondratyev }
286b79de251SVladimir Kondratyev d -= red[i];
287b79de251SVladimir Kondratyev if (d < delta || (d == delta
288b79de251SVladimir Kondratyev && r2c[i] < 0)) {
289b79de251SVladimir Kondratyev delta = d;
290b79de251SVladimir Kondratyev row = i;
291b79de251SVladimir Kondratyev }
292b79de251SVladimir Kondratyev }
293b79de251SVladimir Kondratyev cd[col] += delta;
294b79de251SVladimir Kondratyev for (i = 0; i < k; i++) {
295b79de251SVladimir Kondratyev cd[cs[i]] += delta;
296b79de251SVladimir Kondratyev red[c2r[cs[i]]] -= delta;
297b79de251SVladimir Kondratyev }
298b79de251SVladimir Kondratyev }
299b79de251SVladimir Kondratyev for (j = mc[row]; (r2c[row] = j) != col;) {
300b79de251SVladimir Kondratyev row = c2r[j];
301b79de251SVladimir Kondratyev j = mc[row] + n;
302b79de251SVladimir Kondratyev }
303b79de251SVladimir Kondratyev }
304b79de251SVladimir Kondratyev }
305b79de251SVladimir Kondratyev
306b79de251SVladimir Kondratyev /*
307b79de251SVladimir Kondratyev * Assign tracking IDs to the points in the pt array. The tracking ID
308b79de251SVladimir Kondratyev * assignment pairs the points with points of the previous frame in
309b79de251SVladimir Kondratyev * such a way that the sum of the squared distances is minimal. Using
310b79de251SVladimir Kondratyev * squares instead of simple distances favours assignments with more uniform
311b79de251SVladimir Kondratyev * distances, and it is faster.
312b79de251SVladimir Kondratyev * Set tracking id to -1 for unassigned (new) points.
313b79de251SVladimir Kondratyev */
314b79de251SVladimir Kondratyev void
evdev_mt_match_frame(struct evdev_dev * evdev,union evdev_mt_slot * pt,int size)315b79de251SVladimir Kondratyev evdev_mt_match_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt,
316b79de251SVladimir Kondratyev int size)
317b79de251SVladimir Kondratyev {
318b79de251SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
319b79de251SVladimir Kondratyev int i, j, m, n, dx, dy, slot, num_touches;
320b79de251SVladimir Kondratyev int *p, *r2c, *c2r;
321b79de251SVladimir Kondratyev
322b79de251SVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev);
323b79de251SVladimir Kondratyev MPASS(mt->matrix != NULL);
324b79de251SVladimir Kondratyev MPASS(size >= 0 && size <= MAXIMAL_MT_SLOT(evdev) + 1);
325b79de251SVladimir Kondratyev
326b79de251SVladimir Kondratyev if (size == 0)
327b79de251SVladimir Kondratyev return;
328b79de251SVladimir Kondratyev
329b79de251SVladimir Kondratyev p = mt->matrix;
330b79de251SVladimir Kondratyev num_touches = bitcount(mt->touches);
331b79de251SVladimir Kondratyev if (num_touches >= size) {
332b79de251SVladimir Kondratyev FOREACHBIT(mt->touches, slot)
333b79de251SVladimir Kondratyev for (i = 0; i < size; i++) {
334b79de251SVladimir Kondratyev dx = pt[i].x - mt->slots[slot].x;
335b79de251SVladimir Kondratyev dy = pt[i].y - mt->slots[slot].y;
336b79de251SVladimir Kondratyev *p++ = dx * dx + dy * dy;
337b79de251SVladimir Kondratyev }
338b79de251SVladimir Kondratyev m = num_touches;
339b79de251SVladimir Kondratyev n = size;
340b79de251SVladimir Kondratyev } else {
341b79de251SVladimir Kondratyev for (i = 0; i < size; i++)
342b79de251SVladimir Kondratyev FOREACHBIT(mt->touches, slot) {
343b79de251SVladimir Kondratyev dx = pt[i].x - mt->slots[slot].x;
344b79de251SVladimir Kondratyev dy = pt[i].y - mt->slots[slot].y;
345b79de251SVladimir Kondratyev *p++ = dx * dx + dy * dy;
346b79de251SVladimir Kondratyev }
347b79de251SVladimir Kondratyev m = size;
348b79de251SVladimir Kondratyev n = num_touches;
349b79de251SVladimir Kondratyev }
350b79de251SVladimir Kondratyev evdev_mt_matching(mt->matrix, m, n, p);
351b79de251SVladimir Kondratyev
352b79de251SVladimir Kondratyev r2c = p;
353b79de251SVladimir Kondratyev c2r = p + m;
354b79de251SVladimir Kondratyev for (i = 0; i < m; i++)
355b79de251SVladimir Kondratyev if ((j = r2c[i]) >= 0)
356b79de251SVladimir Kondratyev c2r[j] = i;
357b79de251SVladimir Kondratyev
358b79de251SVladimir Kondratyev p = (n == size ? c2r : r2c);
359b79de251SVladimir Kondratyev for (i = 0; i < size; i++)
360b79de251SVladimir Kondratyev if (*p++ < 0)
361b79de251SVladimir Kondratyev pt[i].id = -1;
362b79de251SVladimir Kondratyev
363b79de251SVladimir Kondratyev p = (n == size ? r2c : c2r);
364b79de251SVladimir Kondratyev FOREACHBIT(mt->touches, slot)
365b79de251SVladimir Kondratyev if ((i = *p++) >= 0)
366b79de251SVladimir Kondratyev pt[i].id = mt->tracking_ids[slot];
367b79de251SVladimir Kondratyev }
368b79de251SVladimir Kondratyev
369b79de251SVladimir Kondratyev static void
evdev_mt_send_frame(struct evdev_dev * evdev,union evdev_mt_slot * pt,int size)370b79de251SVladimir Kondratyev evdev_mt_send_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, int size)
371b79de251SVladimir Kondratyev {
372b79de251SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
373b79de251SVladimir Kondratyev union evdev_mt_slot *slot;
374b79de251SVladimir Kondratyev
375b79de251SVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev);
376b79de251SVladimir Kondratyev MPASS(size >= 0 && size <= MAXIMAL_MT_SLOT(evdev) + 1);
377b79de251SVladimir Kondratyev
378b79de251SVladimir Kondratyev /*
379b79de251SVladimir Kondratyev * While MT-matching assign tracking IDs of new contacts to be equal
380b79de251SVladimir Kondratyev * to a slot number to make things simpler.
381b79de251SVladimir Kondratyev */
382b79de251SVladimir Kondratyev for (slot = pt; slot < pt + size; slot++) {
383b79de251SVladimir Kondratyev if (slot->id < 0)
384b79de251SVladimir Kondratyev slot->id = ffc_slot(evdev, mt->touches | mt->frame);
385b79de251SVladimir Kondratyev if (slot->id >= 0)
386b79de251SVladimir Kondratyev evdev_mt_send_slot(evdev, slot->id, slot);
387b79de251SVladimir Kondratyev }
388b79de251SVladimir Kondratyev }
389b79de251SVladimir Kondratyev
390b79de251SVladimir Kondratyev int
evdev_mt_push_frame(struct evdev_dev * evdev,union evdev_mt_slot * pt,int size)391b79de251SVladimir Kondratyev evdev_mt_push_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, int size)
392b79de251SVladimir Kondratyev {
393b79de251SVladimir Kondratyev if (size < 0 || size > MAXIMAL_MT_SLOT(evdev) + 1)
394b79de251SVladimir Kondratyev return (EINVAL);
395b79de251SVladimir Kondratyev
396b79de251SVladimir Kondratyev EVDEV_ENTER(evdev);
397b79de251SVladimir Kondratyev evdev_mt_send_frame(evdev, pt, size);
398b79de251SVladimir Kondratyev EVDEV_EXIT(evdev);
399b79de251SVladimir Kondratyev
400b79de251SVladimir Kondratyev return (0);
401b79de251SVladimir Kondratyev }
402b79de251SVladimir Kondratyev
4034174302bSVladimir Kondratyev bool
evdev_mt_record_event(struct evdev_dev * evdev,uint16_t type,uint16_t code,int32_t value)4044174302bSVladimir Kondratyev evdev_mt_record_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
4054174302bSVladimir Kondratyev int32_t value)
4064174302bSVladimir Kondratyev {
4074174302bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
4084174302bSVladimir Kondratyev
4094174302bSVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev);
4104174302bSVladimir Kondratyev
4114174302bSVladimir Kondratyev switch (type) {
41245fd5fe9SVladimir Kondratyev case EV_SYN:
41345fd5fe9SVladimir Kondratyev if (code == SYN_MT_REPORT) {
41445fd5fe9SVladimir Kondratyev /* MT protocol type A support */
41545fd5fe9SVladimir Kondratyev KASSERT(mt->type_a, ("Not a MT type A protocol"));
41645fd5fe9SVladimir Kondratyev mt->match_frame |= 1U << mt->match_slot;
41745fd5fe9SVladimir Kondratyev mt->match_slot++;
41845fd5fe9SVladimir Kondratyev return (true);
41945fd5fe9SVladimir Kondratyev }
42045fd5fe9SVladimir Kondratyev break;
4214174302bSVladimir Kondratyev case EV_ABS:
4224174302bSVladimir Kondratyev if (code == ABS_MT_SLOT) {
4234174302bSVladimir Kondratyev /* MT protocol type B support */
42445fd5fe9SVladimir Kondratyev KASSERT(!mt->type_a, ("Not a MT type B protocol"));
4254174302bSVladimir Kondratyev KASSERT(value >= 0, ("Negative slot number"));
4264174302bSVladimir Kondratyev mt->match_slot = value;
4274174302bSVladimir Kondratyev mt->match_frame |= 1U << mt->match_slot;
4284174302bSVladimir Kondratyev return (true);
4294174302bSVladimir Kondratyev } else if (code == ABS_MT_TRACKING_ID) {
43045fd5fe9SVladimir Kondratyev KASSERT(!mt->type_a, ("Not a MT type B protocol"));
4314174302bSVladimir Kondratyev if (value == -1)
4324174302bSVladimir Kondratyev mt->match_frame &= ~(1U << mt->match_slot);
4334174302bSVladimir Kondratyev return (true);
4344174302bSVladimir Kondratyev } else if (ABS_IS_MT(code)) {
4354174302bSVladimir Kondratyev KASSERT(mt->match_slot >= 0, ("Negative slot"));
4364174302bSVladimir Kondratyev KASSERT(mt->match_slot <= MAXIMAL_MT_SLOT(evdev),
4374174302bSVladimir Kondratyev ("Slot number too big"));
4384174302bSVladimir Kondratyev mt->match_slots[mt->match_slot].
4394174302bSVladimir Kondratyev val[ABS_MT_INDEX(code)] = value;
4404174302bSVladimir Kondratyev return (true);
4414174302bSVladimir Kondratyev }
4424174302bSVladimir Kondratyev break;
4434174302bSVladimir Kondratyev default:
4444174302bSVladimir Kondratyev break;
4454174302bSVladimir Kondratyev }
4464174302bSVladimir Kondratyev
4474174302bSVladimir Kondratyev return (false);
4484174302bSVladimir Kondratyev }
4494174302bSVladimir Kondratyev
4504174302bSVladimir Kondratyev static void
evdev_mt_replay_events(struct evdev_dev * evdev)4514174302bSVladimir Kondratyev evdev_mt_replay_events(struct evdev_dev *evdev)
4524174302bSVladimir Kondratyev {
4534174302bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
4544174302bSVladimir Kondratyev int slot, size = 0;
4554174302bSVladimir Kondratyev
4564174302bSVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev);
4574174302bSVladimir Kondratyev
4584174302bSVladimir Kondratyev FOREACHBIT(mt->match_frame, slot) {
4594174302bSVladimir Kondratyev if (slot != size)
4604174302bSVladimir Kondratyev mt->match_slots[size] = mt->match_slots[slot];
4614174302bSVladimir Kondratyev size++;
4624174302bSVladimir Kondratyev }
4634174302bSVladimir Kondratyev evdev_mt_match_frame(evdev, mt->match_slots, size);
4644174302bSVladimir Kondratyev evdev_mt_send_frame(evdev, mt->match_slots, size);
4654174302bSVladimir Kondratyev mt->match_slot = 0;
4664174302bSVladimir Kondratyev mt->match_frame = 0;
4674174302bSVladimir Kondratyev }
4684174302bSVladimir Kondratyev
4694174302bSVladimir Kondratyev union evdev_mt_slot *
evdev_mt_get_match_slots(struct evdev_dev * evdev)4704174302bSVladimir Kondratyev evdev_mt_get_match_slots(struct evdev_dev *evdev)
4714174302bSVladimir Kondratyev {
4724174302bSVladimir Kondratyev return (evdev->ev_mt->match_slots);
4734174302bSVladimir Kondratyev }
4744174302bSVladimir Kondratyev
475a437dfa5SVladimir Kondratyev int
evdev_mt_get_last_slot(struct evdev_dev * evdev)476a437dfa5SVladimir Kondratyev evdev_mt_get_last_slot(struct evdev_dev *evdev)
477a437dfa5SVladimir Kondratyev {
478a437dfa5SVladimir Kondratyev return (evdev->ev_mt->last_reported_slot);
4792b3f6d66SOleksandr Tymoshenko }
4802b3f6d66SOleksandr Tymoshenko
4812b3f6d66SOleksandr Tymoshenko void
evdev_mt_set_last_slot(struct evdev_dev * evdev,int slot)482a437dfa5SVladimir Kondratyev evdev_mt_set_last_slot(struct evdev_dev *evdev, int slot)
4832b3f6d66SOleksandr Tymoshenko {
484a437dfa5SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
4852b3f6d66SOleksandr Tymoshenko
486a437dfa5SVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
4872b3f6d66SOleksandr Tymoshenko
4885bf6cf0fSVladimir Kondratyev mt->frame |= 1U << slot;
489a437dfa5SVladimir Kondratyev mt->last_reported_slot = slot;
4902b3f6d66SOleksandr Tymoshenko }
4912b3f6d66SOleksandr Tymoshenko
4922b3f6d66SOleksandr Tymoshenko int32_t
evdev_mt_get_value(struct evdev_dev * evdev,int slot,int16_t code)493a437dfa5SVladimir Kondratyev evdev_mt_get_value(struct evdev_dev *evdev, int slot, int16_t code)
494a437dfa5SVladimir Kondratyev {
495a437dfa5SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
496a437dfa5SVladimir Kondratyev
497a437dfa5SVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
498a437dfa5SVladimir Kondratyev
499a437dfa5SVladimir Kondratyev return (mt->slots[slot].val[ABS_MT_INDEX(code)]);
500a437dfa5SVladimir Kondratyev }
501a437dfa5SVladimir Kondratyev
502a437dfa5SVladimir Kondratyev void
evdev_mt_set_value(struct evdev_dev * evdev,int slot,int16_t code,int32_t value)503a437dfa5SVladimir Kondratyev evdev_mt_set_value(struct evdev_dev *evdev, int slot, int16_t code,
504a437dfa5SVladimir Kondratyev int32_t value)
505a437dfa5SVladimir Kondratyev {
506a437dfa5SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
507a437dfa5SVladimir Kondratyev
508a437dfa5SVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
509a437dfa5SVladimir Kondratyev
5105bf6cf0fSVladimir Kondratyev if (code == ABS_MT_TRACKING_ID) {
5115bf6cf0fSVladimir Kondratyev if (value != -1)
5125bf6cf0fSVladimir Kondratyev mt->touches |= 1U << slot;
5135bf6cf0fSVladimir Kondratyev else
5145bf6cf0fSVladimir Kondratyev mt->touches &= ~(1U << slot);
5155bf6cf0fSVladimir Kondratyev }
516a437dfa5SVladimir Kondratyev mt->slots[slot].val[ABS_MT_INDEX(code)] = value;
517a437dfa5SVladimir Kondratyev }
518a437dfa5SVladimir Kondratyev
519a437dfa5SVladimir Kondratyev int
evdev_get_mt_slot_by_tracking_id(struct evdev_dev * evdev,int32_t tracking_id)5202b3f6d66SOleksandr Tymoshenko evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id)
5212b3f6d66SOleksandr Tymoshenko {
522a437dfa5SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
5235bf6cf0fSVladimir Kondratyev int slot;
5242b3f6d66SOleksandr Tymoshenko
52545fd5fe9SVladimir Kondratyev KASSERT(!mt->type_a, ("Not a MT type B protocol"));
52645fd5fe9SVladimir Kondratyev
5274174302bSVladimir Kondratyev /*
5284174302bSVladimir Kondratyev * Ignore tracking_id if slot assignment is performed by evdev.
5294174302bSVladimir Kondratyev * Events are written sequentially to temporary matching buffer.
5304174302bSVladimir Kondratyev */
5314174302bSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK))
5324174302bSVladimir Kondratyev return (ffc_slot(evdev, mt->match_frame));
5334174302bSVladimir Kondratyev
5345bf6cf0fSVladimir Kondratyev FOREACHBIT(mt->touches, slot)
535f160aa0dSVladimir Kondratyev if (mt->tracking_ids[slot] == tracking_id)
5362b3f6d66SOleksandr Tymoshenko return (slot);
5372b3f6d66SOleksandr Tymoshenko /*
5385bf6cf0fSVladimir Kondratyev * Do not allow allocation of new slot in a place of just
5395bf6cf0fSVladimir Kondratyev * released one within the same report.
5402b3f6d66SOleksandr Tymoshenko */
5415bf6cf0fSVladimir Kondratyev return (ffc_slot(evdev, mt->touches | mt->frame));
5422b3f6d66SOleksandr Tymoshenko }
5432b3f6d66SOleksandr Tymoshenko
544f160aa0dSVladimir Kondratyev int32_t
evdev_mt_reassign_id(struct evdev_dev * evdev,int slot,int32_t id)545f160aa0dSVladimir Kondratyev evdev_mt_reassign_id(struct evdev_dev *evdev, int slot, int32_t id)
546f160aa0dSVladimir Kondratyev {
547f160aa0dSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
548f160aa0dSVladimir Kondratyev int32_t nid;
549f160aa0dSVladimir Kondratyev
550f160aa0dSVladimir Kondratyev if (id == -1 || bit_test(evdev->ev_flags, EVDEV_FLAG_MT_KEEPID)) {
551f160aa0dSVladimir Kondratyev mt->tracking_ids[slot] = id;
552f160aa0dSVladimir Kondratyev return (id);
553f160aa0dSVladimir Kondratyev }
554f160aa0dSVladimir Kondratyev
555f160aa0dSVladimir Kondratyev nid = evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID);
556f160aa0dSVladimir Kondratyev if (nid != -1) {
557f160aa0dSVladimir Kondratyev KASSERT(id == mt->tracking_ids[slot],
558f160aa0dSVladimir Kondratyev ("MT-slot tracking id has changed"));
559f160aa0dSVladimir Kondratyev return (nid);
560f160aa0dSVladimir Kondratyev }
561f160aa0dSVladimir Kondratyev
562f160aa0dSVladimir Kondratyev mt->tracking_ids[slot] = id;
563f160aa0dSVladimir Kondratyev again:
564f160aa0dSVladimir Kondratyev nid = mt->tracking_id++;
565f160aa0dSVladimir Kondratyev FOREACHBIT(mt->touches, slot)
566f160aa0dSVladimir Kondratyev if (evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID) == nid)
567f160aa0dSVladimir Kondratyev goto again;
568f160aa0dSVladimir Kondratyev
569f160aa0dSVladimir Kondratyev return (nid);
570f160aa0dSVladimir Kondratyev }
571f160aa0dSVladimir Kondratyev
572de6d60eeSVladimir Kondratyev static inline int32_t
evdev_mt_normalize(int32_t value,int32_t mtmin,int32_t mtmax,int32_t stmax)573de6d60eeSVladimir Kondratyev evdev_mt_normalize(int32_t value, int32_t mtmin, int32_t mtmax, int32_t stmax)
574de6d60eeSVladimir Kondratyev {
575de6d60eeSVladimir Kondratyev if (stmax != 0 && mtmax != mtmin) {
576de6d60eeSVladimir Kondratyev value = (value - mtmin) * stmax / (mtmax - mtmin);
577de6d60eeSVladimir Kondratyev value = MAX(MIN(value, stmax), 0);
578de6d60eeSVladimir Kondratyev }
579de6d60eeSVladimir Kondratyev return (value);
580de6d60eeSVladimir Kondratyev }
581de6d60eeSVladimir Kondratyev
5822b3f6d66SOleksandr Tymoshenko void
evdev_support_mt_compat(struct evdev_dev * evdev)5832b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(struct evdev_dev *evdev)
5842b3f6d66SOleksandr Tymoshenko {
585de6d60eeSVladimir Kondratyev struct input_absinfo *ai;
586a437dfa5SVladimir Kondratyev int i;
5872b3f6d66SOleksandr Tymoshenko
5882b3f6d66SOleksandr Tymoshenko if (evdev->ev_absinfo == NULL)
5892b3f6d66SOleksandr Tymoshenko return;
5902b3f6d66SOleksandr Tymoshenko
5912b3f6d66SOleksandr Tymoshenko evdev_support_event(evdev, EV_KEY);
5922b3f6d66SOleksandr Tymoshenko evdev_support_key(evdev, BTN_TOUCH);
5932b3f6d66SOleksandr Tymoshenko
5942b3f6d66SOleksandr Tymoshenko /* Touchscreens should not advertise tap tool capabilities */
5952b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
5962b3f6d66SOleksandr Tymoshenko evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1);
5972b3f6d66SOleksandr Tymoshenko
5982b3f6d66SOleksandr Tymoshenko /* Echo 0-th MT-slot as ST-slot */
599de6d60eeSVladimir Kondratyev for (i = 0; i < nitems(evdev_mtstmap); i++) {
600de6d60eeSVladimir Kondratyev if (!bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].mt) ||
601de6d60eeSVladimir Kondratyev bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].st))
602de6d60eeSVladimir Kondratyev continue;
603de6d60eeSVladimir Kondratyev ai = evdev->ev_absinfo + evdev_mtstmap[i].mt;
604de6d60eeSVladimir Kondratyev evdev->ev_mt->mtst_events |= 1U << i;
605de6d60eeSVladimir Kondratyev if (evdev_mtstmap[i].max != 0)
606de6d60eeSVladimir Kondratyev evdev_support_abs(evdev, evdev_mtstmap[i].st,
607de20578eSVladimir Kondratyev 0,
608de6d60eeSVladimir Kondratyev evdev_mtstmap[i].max,
609de6d60eeSVladimir Kondratyev 0,
610de6d60eeSVladimir Kondratyev evdev_mt_normalize(
611de6d60eeSVladimir Kondratyev ai->flat, 0, ai->maximum, evdev_mtstmap[i].max),
612de6d60eeSVladimir Kondratyev 0);
613de6d60eeSVladimir Kondratyev else
614de6d60eeSVladimir Kondratyev evdev_support_abs(evdev, evdev_mtstmap[i].st,
615de6d60eeSVladimir Kondratyev ai->minimum,
616de6d60eeSVladimir Kondratyev ai->maximum,
617de6d60eeSVladimir Kondratyev 0,
618de6d60eeSVladimir Kondratyev ai->flat,
619de6d60eeSVladimir Kondratyev ai->resolution);
620de6d60eeSVladimir Kondratyev }
6212b3f6d66SOleksandr Tymoshenko }
6222b3f6d66SOleksandr Tymoshenko
6232b3f6d66SOleksandr Tymoshenko static void
evdev_mt_send_st_compat(struct evdev_dev * evdev)624a437dfa5SVladimir Kondratyev evdev_mt_send_st_compat(struct evdev_dev *evdev)
6252b3f6d66SOleksandr Tymoshenko {
6265bf6cf0fSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
627f7d9821cSVladimir Kondratyev int nfingers, i, st_slot;
6282b3f6d66SOleksandr Tymoshenko
6292b3f6d66SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev);
6302b3f6d66SOleksandr Tymoshenko
6315bf6cf0fSVladimir Kondratyev nfingers = bitcount(mt->touches);
6322b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0);
6332b3f6d66SOleksandr Tymoshenko
634f7d9821cSVladimir Kondratyev /* Send first active MT-slot state as single touch report */
635f7d9821cSVladimir Kondratyev st_slot = ffs(mt->touches) - 1;
636f7d9821cSVladimir Kondratyev if (st_slot != -1)
637de6d60eeSVladimir Kondratyev FOREACHBIT(mt->mtst_events, i)
638de6d60eeSVladimir Kondratyev evdev_send_event(evdev, EV_ABS, evdev_mtstmap[i].st,
639de6d60eeSVladimir Kondratyev evdev_mt_normalize(evdev_mt_get_value(evdev,
640de6d60eeSVladimir Kondratyev st_slot, evdev_mtstmap[i].mt),
641de6d60eeSVladimir Kondratyev evdev->ev_absinfo[evdev_mtstmap[i].mt].minimum,
642de6d60eeSVladimir Kondratyev evdev->ev_absinfo[evdev_mtstmap[i].mt].maximum,
643de6d60eeSVladimir Kondratyev evdev_mtstmap[i].max));
6442b3f6d66SOleksandr Tymoshenko
6452b3f6d66SOleksandr Tymoshenko /* Touchscreens should not report tool taps */
6462b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
6472b3f6d66SOleksandr Tymoshenko evdev_send_nfingers(evdev, nfingers);
6482b3f6d66SOleksandr Tymoshenko
6492b3f6d66SOleksandr Tymoshenko if (nfingers == 0)
6502b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0);
6512b3f6d66SOleksandr Tymoshenko }
6522b3f6d66SOleksandr Tymoshenko
6532b3f6d66SOleksandr Tymoshenko void
evdev_push_mt_compat(struct evdev_dev * evdev)6542b3f6d66SOleksandr Tymoshenko evdev_push_mt_compat(struct evdev_dev *evdev)
6552b3f6d66SOleksandr Tymoshenko {
6562b3f6d66SOleksandr Tymoshenko
6574c0a4665SVladimir Kondratyev EVDEV_ENTER(evdev);
658a437dfa5SVladimir Kondratyev evdev_mt_send_st_compat(evdev);
6594c0a4665SVladimir Kondratyev EVDEV_EXIT(evdev);
6602b3f6d66SOleksandr Tymoshenko }
661c736a757SOleksandr Tymoshenko
662a437dfa5SVladimir Kondratyev static void
evdev_mt_send_autorel(struct evdev_dev * evdev)663a437dfa5SVladimir Kondratyev evdev_mt_send_autorel(struct evdev_dev *evdev)
664c736a757SOleksandr Tymoshenko {
665a437dfa5SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
666a437dfa5SVladimir Kondratyev int slot;
667c736a757SOleksandr Tymoshenko
668c736a757SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev);
6694174302bSVladimir Kondratyev KASSERT(mt->match_frame == 0, ("Unmatched events exist"));
670c736a757SOleksandr Tymoshenko
671759a5cd1SVladimir Kondratyev FOREACHBIT(mt->touches & ~mt->frame, slot)
672759a5cd1SVladimir Kondratyev evdev_mt_send_slot(evdev, slot, NULL);
673c736a757SOleksandr Tymoshenko }
674a437dfa5SVladimir Kondratyev
675a437dfa5SVladimir Kondratyev void
evdev_mt_push_autorel(struct evdev_dev * evdev)676a437dfa5SVladimir Kondratyev evdev_mt_push_autorel(struct evdev_dev *evdev)
677a437dfa5SVladimir Kondratyev {
678a437dfa5SVladimir Kondratyev EVDEV_ENTER(evdev);
679a437dfa5SVladimir Kondratyev evdev_mt_send_autorel(evdev);
680a437dfa5SVladimir Kondratyev EVDEV_EXIT(evdev);
681a437dfa5SVladimir Kondratyev }
682