12b3f6d66SOleksandr Tymoshenko /*-
2f76051c7SVladimir Kondratyev * Copyright (c) 2016, 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
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 */
264c0a134eSVladimir Kondratyev /*-
274c0a134eSVladimir Kondratyev * Copyright (c) 2015, 2016 Ulf Brosziewski
284c0a134eSVladimir Kondratyev *
294c0a134eSVladimir Kondratyev * Permission to use, copy, modify, and distribute this software for any
304c0a134eSVladimir Kondratyev * purpose with or without fee is hereby granted, provided that the above
314c0a134eSVladimir Kondratyev * copyright notice and this permission notice appear in all copies.
324c0a134eSVladimir Kondratyev *
334c0a134eSVladimir Kondratyev * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
344c0a134eSVladimir Kondratyev * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
354c0a134eSVladimir Kondratyev * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
364c0a134eSVladimir Kondratyev * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
374c0a134eSVladimir Kondratyev * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
384c0a134eSVladimir Kondratyev * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
394c0a134eSVladimir Kondratyev * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
404c0a134eSVladimir Kondratyev */
412b3f6d66SOleksandr Tymoshenko
422b3f6d66SOleksandr Tymoshenko #include <sys/param.h>
432b3f6d66SOleksandr Tymoshenko #include <sys/lock.h>
44ea2e26b1SVladimir Kondratyev #include <sys/malloc.h>
452b3f6d66SOleksandr Tymoshenko #include <sys/mutex.h>
462b3f6d66SOleksandr Tymoshenko #include <sys/systm.h>
472b3f6d66SOleksandr Tymoshenko
482b3f6d66SOleksandr Tymoshenko #include <dev/evdev/evdev.h>
492b3f6d66SOleksandr Tymoshenko #include <dev/evdev/evdev_private.h>
50ea2e26b1SVladimir Kondratyev #include <dev/evdev/input.h>
512b3f6d66SOleksandr Tymoshenko
522b3f6d66SOleksandr Tymoshenko #ifdef DEBUG
532b3f6d66SOleksandr Tymoshenko #define debugf(fmt, args...) printf("evdev: " fmt "\n", ##args)
542b3f6d66SOleksandr Tymoshenko #else
552b3f6d66SOleksandr Tymoshenko #define debugf(fmt, args...)
562b3f6d66SOleksandr Tymoshenko #endif
572b3f6d66SOleksandr Tymoshenko
582dc7188eSVladimir Kondratyev typedef u_int slotset_t;
592dc7188eSVladimir Kondratyev
602dc7188eSVladimir Kondratyev _Static_assert(MAX_MT_SLOTS < sizeof(slotset_t) * 8, "MAX_MT_SLOTS too big");
612dc7188eSVladimir Kondratyev
622dc7188eSVladimir Kondratyev #define FOREACHBIT(v, i) \
632dc7188eSVladimir Kondratyev for ((i) = ffs(v) - 1; (i) != -1; (i) = ffs((v) & (~1 << (i))) - 1)
642dc7188eSVladimir Kondratyev
65127e54deSVladimir Kondratyev struct {
66127e54deSVladimir Kondratyev uint16_t mt;
67127e54deSVladimir Kondratyev uint16_t st;
68127e54deSVladimir Kondratyev int32_t max;
69127e54deSVladimir Kondratyev } static evdev_mtstmap[] = {
70127e54deSVladimir Kondratyev { ABS_MT_POSITION_X, ABS_X, 0 },
71127e54deSVladimir Kondratyev { ABS_MT_POSITION_Y, ABS_Y, 0 },
72127e54deSVladimir Kondratyev { ABS_MT_PRESSURE, ABS_PRESSURE, 255 },
73127e54deSVladimir Kondratyev { ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH, 15 },
742b3f6d66SOleksandr Tymoshenko };
752b3f6d66SOleksandr Tymoshenko
762b3f6d66SOleksandr Tymoshenko struct evdev_mt {
7798a7606bSVladimir Kondratyev int last_reported_slot;
7866bd52f5SVladimir Kondratyev uint16_t tracking_id;
7966bd52f5SVladimir Kondratyev int32_t tracking_ids[MAX_MT_SLOTS];
80d056693dSVladimir Kondratyev bool type_a;
81127e54deSVladimir Kondratyev u_int mtst_events;
822dc7188eSVladimir Kondratyev /* the set of slots with active touches */
832dc7188eSVladimir Kondratyev slotset_t touches;
842dc7188eSVladimir Kondratyev /* the set of slots with unsynchronized state */
852dc7188eSVladimir Kondratyev slotset_t frame;
86f76051c7SVladimir Kondratyev /* the set of slots to match with active touches */
87f76051c7SVladimir Kondratyev slotset_t match_frame;
88f76051c7SVladimir Kondratyev int match_slot;
89f76051c7SVladimir Kondratyev union evdev_mt_slot *match_slots;
904c0a134eSVladimir Kondratyev int *matrix;
9105936028SVladimir Kondratyev union evdev_mt_slot slots[];
922b3f6d66SOleksandr Tymoshenko };
932b3f6d66SOleksandr Tymoshenko
9435bc295bSVladimir Kondratyev static void evdev_mt_support_st_compat(struct evdev_dev *);
9598a7606bSVladimir Kondratyev static void evdev_mt_send_st_compat(struct evdev_dev *);
9698a7606bSVladimir Kondratyev static void evdev_mt_send_autorel(struct evdev_dev *);
97f76051c7SVladimir Kondratyev static void evdev_mt_replay_events(struct evdev_dev *);
9898a7606bSVladimir Kondratyev
992dc7188eSVladimir Kondratyev static inline int
ffc_slot(struct evdev_dev * evdev,slotset_t slots)1002dc7188eSVladimir Kondratyev ffc_slot(struct evdev_dev *evdev, slotset_t slots)
1012dc7188eSVladimir Kondratyev {
102*d99c87c8SJohn Baldwin return (ffs(~slots & ((2U << MAXIMAL_MT_SLOT(evdev)) - 1)) - 1);
1032dc7188eSVladimir Kondratyev }
1042dc7188eSVladimir Kondratyev
1052b3f6d66SOleksandr Tymoshenko void
evdev_mt_init(struct evdev_dev * evdev)1062b3f6d66SOleksandr Tymoshenko evdev_mt_init(struct evdev_dev *evdev)
1072b3f6d66SOleksandr Tymoshenko {
1084c0a134eSVladimir Kondratyev struct evdev_mt *mt;
1094c0a134eSVladimir Kondratyev size_t size = offsetof(struct evdev_mt, slots);
11098a7606bSVladimir Kondratyev int slot, slots;
111d056693dSVladimir Kondratyev bool type_a;
112d056693dSVladimir Kondratyev
113d056693dSVladimir Kondratyev type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT);
114d056693dSVladimir Kondratyev if (type_a) {
115d056693dSVladimir Kondratyev /* Add events produced by MT type A to type B converter */
116d056693dSVladimir Kondratyev evdev_support_abs(evdev,
117d056693dSVladimir Kondratyev ABS_MT_SLOT, 0, MAX_MT_SLOTS - 1, 0, 0, 0);
118d056693dSVladimir Kondratyev evdev_support_abs(evdev,
119d056693dSVladimir Kondratyev ABS_MT_TRACKING_ID, -1, MAX_MT_SLOTS - 1, 0, 0, 0);
120d056693dSVladimir Kondratyev }
1212b3f6d66SOleksandr Tymoshenko
1222b3f6d66SOleksandr Tymoshenko slots = MAXIMAL_MT_SLOT(evdev) + 1;
1234c0a134eSVladimir Kondratyev size += sizeof(mt->slots[0]) * slots;
1244c0a134eSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) {
125f76051c7SVladimir Kondratyev size += sizeof(mt->match_slots[0]) * slots;
1264c0a134eSVladimir Kondratyev size += sizeof(mt->matrix[0]) * (slots + 6) * slots;
1274c0a134eSVladimir Kondratyev }
1282b3f6d66SOleksandr Tymoshenko
1294c0a134eSVladimir Kondratyev mt = malloc(size, M_EVDEV, M_WAITOK | M_ZERO);
1304c0a134eSVladimir Kondratyev evdev->ev_mt = mt;
131d056693dSVladimir Kondratyev mt->type_a = type_a;
1324c0a134eSVladimir Kondratyev
1334c0a134eSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) {
134f76051c7SVladimir Kondratyev mt->match_slots = mt->slots + slots;
135f76051c7SVladimir Kondratyev mt->matrix = (int *)(mt->match_slots + slots);
1364c0a134eSVladimir Kondratyev }
1372b3f6d66SOleksandr Tymoshenko
1382b3f6d66SOleksandr Tymoshenko /* Initialize multitouch protocol type B states */
1392dc7188eSVladimir Kondratyev for (slot = 0; slot < slots; slot++)
140f76051c7SVladimir Kondratyev mt->slots[slot].id = -1;
1412b3f6d66SOleksandr Tymoshenko
14266bd52f5SVladimir Kondratyev if (!bit_test(evdev->ev_flags, EVDEV_FLAG_MT_KEEPID))
14366bd52f5SVladimir Kondratyev evdev_support_abs(evdev,
14466bd52f5SVladimir Kondratyev ABS_MT_TRACKING_ID, -1, UINT16_MAX, 0, 0, 0);
1452b3f6d66SOleksandr Tymoshenko if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
14635bc295bSVladimir Kondratyev evdev_mt_support_st_compat(evdev);
1472b3f6d66SOleksandr Tymoshenko }
1482b3f6d66SOleksandr Tymoshenko
1492b3f6d66SOleksandr Tymoshenko void
evdev_mt_free(struct evdev_dev * evdev)1502b3f6d66SOleksandr Tymoshenko evdev_mt_free(struct evdev_dev *evdev)
1512b3f6d66SOleksandr Tymoshenko {
1522b3f6d66SOleksandr Tymoshenko free(evdev->ev_mt, M_EVDEV);
1532b3f6d66SOleksandr Tymoshenko }
1542b3f6d66SOleksandr Tymoshenko
15598a7606bSVladimir Kondratyev void
evdev_mt_sync_frame(struct evdev_dev * evdev)15698a7606bSVladimir Kondratyev evdev_mt_sync_frame(struct evdev_dev *evdev)
1572b3f6d66SOleksandr Tymoshenko {
158f76051c7SVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK))
159f76051c7SVladimir Kondratyev evdev_mt_replay_events(evdev);
16098a7606bSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL))
16198a7606bSVladimir Kondratyev evdev_mt_send_autorel(evdev);
16298a7606bSVladimir Kondratyev if (evdev->ev_report_opened &&
16398a7606bSVladimir Kondratyev bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
16498a7606bSVladimir Kondratyev evdev_mt_send_st_compat(evdev);
1652dc7188eSVladimir Kondratyev evdev->ev_mt->frame = 0;
16698a7606bSVladimir Kondratyev }
1672b3f6d66SOleksandr Tymoshenko
16805936028SVladimir Kondratyev static void
evdev_mt_send_slot(struct evdev_dev * evdev,int slot,union evdev_mt_slot * state)16905936028SVladimir Kondratyev evdev_mt_send_slot(struct evdev_dev *evdev, int slot,
17005936028SVladimir Kondratyev union evdev_mt_slot *state)
17105936028SVladimir Kondratyev {
17205936028SVladimir Kondratyev int i;
17305936028SVladimir Kondratyev bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT);
17405936028SVladimir Kondratyev
17505936028SVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev);
17605936028SVladimir Kondratyev MPASS(type_a || (slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)));
17705936028SVladimir Kondratyev MPASS(!type_a || state != NULL);
17805936028SVladimir Kondratyev
17905936028SVladimir Kondratyev if (!type_a) {
18005936028SVladimir Kondratyev evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot);
18105936028SVladimir Kondratyev if (state == NULL) {
18205936028SVladimir Kondratyev evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID, -1);
18305936028SVladimir Kondratyev return;
18405936028SVladimir Kondratyev }
18505936028SVladimir Kondratyev }
18605936028SVladimir Kondratyev bit_foreach_at(evdev->ev_abs_flags, ABS_MT_FIRST, ABS_MT_LAST + 1, i)
18705936028SVladimir Kondratyev evdev_send_event(evdev, EV_ABS, i,
18805936028SVladimir Kondratyev state->val[ABS_MT_INDEX(i)]);
18905936028SVladimir Kondratyev if (type_a)
19005936028SVladimir Kondratyev evdev_send_event(evdev, EV_SYN, SYN_MT_REPORT, 1);
19105936028SVladimir Kondratyev }
19205936028SVladimir Kondratyev
19305936028SVladimir Kondratyev int
evdev_mt_push_slot(struct evdev_dev * evdev,int slot,union evdev_mt_slot * state)19405936028SVladimir Kondratyev evdev_mt_push_slot(struct evdev_dev *evdev, int slot,
19505936028SVladimir Kondratyev union evdev_mt_slot *state)
19605936028SVladimir Kondratyev {
197f76051c7SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
19805936028SVladimir Kondratyev bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT);
19905936028SVladimir Kondratyev
200d056693dSVladimir Kondratyev if ((type_a || (mt != NULL && mt->type_a)) && state == NULL)
20105936028SVladimir Kondratyev return (EINVAL);
20205936028SVladimir Kondratyev if (!type_a && (slot < 0 || slot > MAXIMAL_MT_SLOT(evdev)))
20305936028SVladimir Kondratyev return (EINVAL);
20405936028SVladimir Kondratyev
20505936028SVladimir Kondratyev EVDEV_ENTER(evdev);
206d056693dSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK) && mt->type_a) {
207d056693dSVladimir Kondratyev mt->match_slots[mt->match_slot] = *state;
208d056693dSVladimir Kondratyev evdev_mt_record_event(evdev, EV_SYN, SYN_MT_REPORT, 1);
209d056693dSVladimir Kondratyev } else if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) {
210f76051c7SVladimir Kondratyev evdev_mt_record_event(evdev, EV_ABS, ABS_MT_SLOT, slot);
211f76051c7SVladimir Kondratyev if (state != NULL)
212f76051c7SVladimir Kondratyev mt->match_slots[mt->match_slot] = *state;
213f76051c7SVladimir Kondratyev else
214f76051c7SVladimir Kondratyev evdev_mt_record_event(evdev, EV_ABS,
215f76051c7SVladimir Kondratyev ABS_MT_TRACKING_ID, -1);
216f76051c7SVladimir Kondratyev } else
21705936028SVladimir Kondratyev evdev_mt_send_slot(evdev, slot, state);
21805936028SVladimir Kondratyev EVDEV_EXIT(evdev);
21905936028SVladimir Kondratyev
22005936028SVladimir Kondratyev return (0);
22105936028SVladimir Kondratyev }
22205936028SVladimir Kondratyev
2234c0a134eSVladimir Kondratyev /*
2244c0a134eSVladimir Kondratyev * Find a minimum-weight matching for an m-by-n matrix.
2254c0a134eSVladimir Kondratyev *
2264c0a134eSVladimir Kondratyev * m must be greater than or equal to n. The size of the buffer must be
2274c0a134eSVladimir Kondratyev * at least 3m + 3n.
2284c0a134eSVladimir Kondratyev *
2294c0a134eSVladimir Kondratyev * On return, the first m elements of the buffer contain the row-to-
2304c0a134eSVladimir Kondratyev * column mappings, i.e., buffer[i] is the column index for row i, or -1
2314c0a134eSVladimir Kondratyev * if there is no assignment for that row (which may happen if n < m).
2324c0a134eSVladimir Kondratyev *
2334c0a134eSVladimir Kondratyev * Wrong results because of overflows will not occur with input values
2344c0a134eSVladimir Kondratyev * in the range of 0 to INT_MAX / 2 inclusive.
2354c0a134eSVladimir Kondratyev *
2364c0a134eSVladimir Kondratyev * The function applies the Dinic-Kronrod algorithm. It is not modern or
2374c0a134eSVladimir Kondratyev * popular, but it seems to be a good choice for small matrices at least.
2384c0a134eSVladimir Kondratyev * The original form of the algorithm is modified as follows: There is no
2394c0a134eSVladimir Kondratyev * initial search for row minima, the initial assignments are in a
2404c0a134eSVladimir Kondratyev * "virtual" column with the index -1 and zero values. This permits inputs
2414c0a134eSVladimir Kondratyev * with n < m, and it simplifies the reassignments.
2424c0a134eSVladimir Kondratyev */
2434c0a134eSVladimir Kondratyev static void
evdev_mt_matching(int * matrix,int m,int n,int * buffer)2444c0a134eSVladimir Kondratyev evdev_mt_matching(int *matrix, int m, int n, int *buffer)
2454c0a134eSVladimir Kondratyev {
2464c0a134eSVladimir Kondratyev int i, j, k, d, e, row, col, delta;
2474c0a134eSVladimir Kondratyev int *p;
2484c0a134eSVladimir Kondratyev int *r2c = buffer; /* row-to-column assignments */
2494c0a134eSVladimir Kondratyev int *red = r2c + m; /* reduced values of the assignments */
2504c0a134eSVladimir Kondratyev int *mc = red + m; /* row-wise minimal elements of cs */
2514c0a134eSVladimir Kondratyev int *cs = mc + m; /* the column set */
2524c0a134eSVladimir Kondratyev int *c2r = cs + n; /* column-to-row assignments in cs */
2534c0a134eSVladimir Kondratyev int *cd = c2r + n; /* column deltas (reduction) */
2544c0a134eSVladimir Kondratyev
2554c0a134eSVladimir Kondratyev for (p = r2c; p < red; *p++ = -1) {}
2564c0a134eSVladimir Kondratyev for (; p < mc; *p++ = 0) {}
2574c0a134eSVladimir Kondratyev for (col = 0; col < n; col++) {
2584c0a134eSVladimir Kondratyev delta = INT_MAX;
2594c0a134eSVladimir Kondratyev for (i = 0, p = matrix + col; i < m; i++, p += n) {
2604c0a134eSVladimir Kondratyev d = *p - red[i];
2614c0a134eSVladimir Kondratyev if (d < delta || (d == delta && r2c[i] < 0)) {
2624c0a134eSVladimir Kondratyev delta = d;
2634c0a134eSVladimir Kondratyev row = i;
2644c0a134eSVladimir Kondratyev }
2654c0a134eSVladimir Kondratyev }
2664c0a134eSVladimir Kondratyev cd[col] = delta;
2674c0a134eSVladimir Kondratyev if (r2c[row] < 0) {
2684c0a134eSVladimir Kondratyev r2c[row] = col;
2694c0a134eSVladimir Kondratyev continue;
2704c0a134eSVladimir Kondratyev }
2714c0a134eSVladimir Kondratyev for (p = mc; p < cs; *p++ = col) {}
2724c0a134eSVladimir Kondratyev for (k = 0; (j = r2c[row]) >= 0;) {
2734c0a134eSVladimir Kondratyev cs[k++] = j;
2744c0a134eSVladimir Kondratyev c2r[j] = row;
2754c0a134eSVladimir Kondratyev mc[row] -= n;
2764c0a134eSVladimir Kondratyev delta = INT_MAX;
2774c0a134eSVladimir Kondratyev for (i = 0, p = matrix; i < m; i++, p += n)
2784c0a134eSVladimir Kondratyev if (mc[i] >= 0) {
2794c0a134eSVladimir Kondratyev d = p[mc[i]] - cd[mc[i]];
2804c0a134eSVladimir Kondratyev e = p[j] - cd[j];
2814c0a134eSVladimir Kondratyev if (e < d) {
2824c0a134eSVladimir Kondratyev d = e;
2834c0a134eSVladimir Kondratyev mc[i] = j;
2844c0a134eSVladimir Kondratyev }
2854c0a134eSVladimir Kondratyev d -= red[i];
2864c0a134eSVladimir Kondratyev if (d < delta || (d == delta
2874c0a134eSVladimir Kondratyev && r2c[i] < 0)) {
2884c0a134eSVladimir Kondratyev delta = d;
2894c0a134eSVladimir Kondratyev row = i;
2904c0a134eSVladimir Kondratyev }
2914c0a134eSVladimir Kondratyev }
2924c0a134eSVladimir Kondratyev cd[col] += delta;
2934c0a134eSVladimir Kondratyev for (i = 0; i < k; i++) {
2944c0a134eSVladimir Kondratyev cd[cs[i]] += delta;
2954c0a134eSVladimir Kondratyev red[c2r[cs[i]]] -= delta;
2964c0a134eSVladimir Kondratyev }
2974c0a134eSVladimir Kondratyev }
2984c0a134eSVladimir Kondratyev for (j = mc[row]; (r2c[row] = j) != col;) {
2994c0a134eSVladimir Kondratyev row = c2r[j];
3004c0a134eSVladimir Kondratyev j = mc[row] + n;
3014c0a134eSVladimir Kondratyev }
3024c0a134eSVladimir Kondratyev }
3034c0a134eSVladimir Kondratyev }
3044c0a134eSVladimir Kondratyev
3054c0a134eSVladimir Kondratyev /*
3064c0a134eSVladimir Kondratyev * Assign tracking IDs to the points in the pt array. The tracking ID
3074c0a134eSVladimir Kondratyev * assignment pairs the points with points of the previous frame in
3084c0a134eSVladimir Kondratyev * such a way that the sum of the squared distances is minimal. Using
3094c0a134eSVladimir Kondratyev * squares instead of simple distances favours assignments with more uniform
3104c0a134eSVladimir Kondratyev * distances, and it is faster.
3114c0a134eSVladimir Kondratyev * Set tracking id to -1 for unassigned (new) points.
3124c0a134eSVladimir Kondratyev */
3134c0a134eSVladimir Kondratyev void
evdev_mt_match_frame(struct evdev_dev * evdev,union evdev_mt_slot * pt,int size)3144c0a134eSVladimir Kondratyev evdev_mt_match_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt,
3154c0a134eSVladimir Kondratyev int size)
3164c0a134eSVladimir Kondratyev {
3174c0a134eSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
3184c0a134eSVladimir Kondratyev int i, j, m, n, dx, dy, slot, num_touches;
3194c0a134eSVladimir Kondratyev int *p, *r2c, *c2r;
3204c0a134eSVladimir Kondratyev
3214c0a134eSVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev);
3224c0a134eSVladimir Kondratyev MPASS(mt->matrix != NULL);
3234c0a134eSVladimir Kondratyev MPASS(size >= 0 && size <= MAXIMAL_MT_SLOT(evdev) + 1);
3244c0a134eSVladimir Kondratyev
3254c0a134eSVladimir Kondratyev if (size == 0)
3264c0a134eSVladimir Kondratyev return;
3274c0a134eSVladimir Kondratyev
3284c0a134eSVladimir Kondratyev p = mt->matrix;
3294c0a134eSVladimir Kondratyev num_touches = bitcount(mt->touches);
3304c0a134eSVladimir Kondratyev if (num_touches >= size) {
3314c0a134eSVladimir Kondratyev FOREACHBIT(mt->touches, slot)
3324c0a134eSVladimir Kondratyev for (i = 0; i < size; i++) {
3334c0a134eSVladimir Kondratyev dx = pt[i].x - mt->slots[slot].x;
3344c0a134eSVladimir Kondratyev dy = pt[i].y - mt->slots[slot].y;
3354c0a134eSVladimir Kondratyev *p++ = dx * dx + dy * dy;
3364c0a134eSVladimir Kondratyev }
3374c0a134eSVladimir Kondratyev m = num_touches;
3384c0a134eSVladimir Kondratyev n = size;
3394c0a134eSVladimir Kondratyev } else {
3404c0a134eSVladimir Kondratyev for (i = 0; i < size; i++)
3414c0a134eSVladimir Kondratyev FOREACHBIT(mt->touches, slot) {
3424c0a134eSVladimir Kondratyev dx = pt[i].x - mt->slots[slot].x;
3434c0a134eSVladimir Kondratyev dy = pt[i].y - mt->slots[slot].y;
3444c0a134eSVladimir Kondratyev *p++ = dx * dx + dy * dy;
3454c0a134eSVladimir Kondratyev }
3464c0a134eSVladimir Kondratyev m = size;
3474c0a134eSVladimir Kondratyev n = num_touches;
3484c0a134eSVladimir Kondratyev }
3494c0a134eSVladimir Kondratyev evdev_mt_matching(mt->matrix, m, n, p);
3504c0a134eSVladimir Kondratyev
3514c0a134eSVladimir Kondratyev r2c = p;
3524c0a134eSVladimir Kondratyev c2r = p + m;
3534c0a134eSVladimir Kondratyev for (i = 0; i < m; i++)
3544c0a134eSVladimir Kondratyev if ((j = r2c[i]) >= 0)
3554c0a134eSVladimir Kondratyev c2r[j] = i;
3564c0a134eSVladimir Kondratyev
3574c0a134eSVladimir Kondratyev p = (n == size ? c2r : r2c);
3584c0a134eSVladimir Kondratyev for (i = 0; i < size; i++)
3594c0a134eSVladimir Kondratyev if (*p++ < 0)
3604c0a134eSVladimir Kondratyev pt[i].id = -1;
3614c0a134eSVladimir Kondratyev
3624c0a134eSVladimir Kondratyev p = (n == size ? r2c : c2r);
3634c0a134eSVladimir Kondratyev FOREACHBIT(mt->touches, slot)
3644c0a134eSVladimir Kondratyev if ((i = *p++) >= 0)
3654c0a134eSVladimir Kondratyev pt[i].id = mt->tracking_ids[slot];
3664c0a134eSVladimir Kondratyev }
3674c0a134eSVladimir Kondratyev
3684c0a134eSVladimir Kondratyev static void
evdev_mt_send_frame(struct evdev_dev * evdev,union evdev_mt_slot * pt,int size)3694c0a134eSVladimir Kondratyev evdev_mt_send_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, int size)
3704c0a134eSVladimir Kondratyev {
3714c0a134eSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
3724c0a134eSVladimir Kondratyev union evdev_mt_slot *slot;
3734c0a134eSVladimir Kondratyev
3744c0a134eSVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev);
3754c0a134eSVladimir Kondratyev MPASS(size >= 0 && size <= MAXIMAL_MT_SLOT(evdev) + 1);
3764c0a134eSVladimir Kondratyev
3774c0a134eSVladimir Kondratyev /*
3784c0a134eSVladimir Kondratyev * While MT-matching assign tracking IDs of new contacts to be equal
3794c0a134eSVladimir Kondratyev * to a slot number to make things simpler.
3804c0a134eSVladimir Kondratyev */
3814c0a134eSVladimir Kondratyev for (slot = pt; slot < pt + size; slot++) {
3824c0a134eSVladimir Kondratyev if (slot->id < 0)
3834c0a134eSVladimir Kondratyev slot->id = ffc_slot(evdev, mt->touches | mt->frame);
3844c0a134eSVladimir Kondratyev if (slot->id >= 0)
3854c0a134eSVladimir Kondratyev evdev_mt_send_slot(evdev, slot->id, slot);
3864c0a134eSVladimir Kondratyev }
3874c0a134eSVladimir Kondratyev }
3884c0a134eSVladimir Kondratyev
3894c0a134eSVladimir Kondratyev int
evdev_mt_push_frame(struct evdev_dev * evdev,union evdev_mt_slot * pt,int size)3904c0a134eSVladimir Kondratyev evdev_mt_push_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, int size)
3914c0a134eSVladimir Kondratyev {
3924c0a134eSVladimir Kondratyev if (size < 0 || size > MAXIMAL_MT_SLOT(evdev) + 1)
3934c0a134eSVladimir Kondratyev return (EINVAL);
3944c0a134eSVladimir Kondratyev
3954c0a134eSVladimir Kondratyev EVDEV_ENTER(evdev);
3964c0a134eSVladimir Kondratyev evdev_mt_send_frame(evdev, pt, size);
3974c0a134eSVladimir Kondratyev EVDEV_EXIT(evdev);
3984c0a134eSVladimir Kondratyev
3994c0a134eSVladimir Kondratyev return (0);
4004c0a134eSVladimir Kondratyev }
4014c0a134eSVladimir Kondratyev
402f76051c7SVladimir Kondratyev bool
evdev_mt_record_event(struct evdev_dev * evdev,uint16_t type,uint16_t code,int32_t value)403f76051c7SVladimir Kondratyev evdev_mt_record_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
404f76051c7SVladimir Kondratyev int32_t value)
405f76051c7SVladimir Kondratyev {
406f76051c7SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
407f76051c7SVladimir Kondratyev
408f76051c7SVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev);
409f76051c7SVladimir Kondratyev
410f76051c7SVladimir Kondratyev switch (type) {
411d056693dSVladimir Kondratyev case EV_SYN:
412d056693dSVladimir Kondratyev if (code == SYN_MT_REPORT) {
413d056693dSVladimir Kondratyev /* MT protocol type A support */
414d056693dSVladimir Kondratyev KASSERT(mt->type_a, ("Not a MT type A protocol"));
415d056693dSVladimir Kondratyev mt->match_frame |= 1U << mt->match_slot;
416d056693dSVladimir Kondratyev mt->match_slot++;
417d056693dSVladimir Kondratyev return (true);
418d056693dSVladimir Kondratyev }
419d056693dSVladimir Kondratyev break;
420f76051c7SVladimir Kondratyev case EV_ABS:
421f76051c7SVladimir Kondratyev if (code == ABS_MT_SLOT) {
422f76051c7SVladimir Kondratyev /* MT protocol type B support */
423d056693dSVladimir Kondratyev KASSERT(!mt->type_a, ("Not a MT type B protocol"));
424f76051c7SVladimir Kondratyev KASSERT(value >= 0, ("Negative slot number"));
425f76051c7SVladimir Kondratyev mt->match_slot = value;
426f76051c7SVladimir Kondratyev mt->match_frame |= 1U << mt->match_slot;
427f76051c7SVladimir Kondratyev return (true);
428f76051c7SVladimir Kondratyev } else if (code == ABS_MT_TRACKING_ID) {
429d056693dSVladimir Kondratyev KASSERT(!mt->type_a, ("Not a MT type B protocol"));
430f76051c7SVladimir Kondratyev if (value == -1)
431f76051c7SVladimir Kondratyev mt->match_frame &= ~(1U << mt->match_slot);
432f76051c7SVladimir Kondratyev return (true);
433f76051c7SVladimir Kondratyev } else if (ABS_IS_MT(code)) {
434f76051c7SVladimir Kondratyev KASSERT(mt->match_slot >= 0, ("Negative slot"));
435f76051c7SVladimir Kondratyev KASSERT(mt->match_slot <= MAXIMAL_MT_SLOT(evdev),
436f76051c7SVladimir Kondratyev ("Slot number too big"));
437f76051c7SVladimir Kondratyev mt->match_slots[mt->match_slot].
438f76051c7SVladimir Kondratyev val[ABS_MT_INDEX(code)] = value;
439f76051c7SVladimir Kondratyev return (true);
440f76051c7SVladimir Kondratyev }
441f76051c7SVladimir Kondratyev break;
442f76051c7SVladimir Kondratyev default:
443f76051c7SVladimir Kondratyev break;
444f76051c7SVladimir Kondratyev }
445f76051c7SVladimir Kondratyev
446f76051c7SVladimir Kondratyev return (false);
447f76051c7SVladimir Kondratyev }
448f76051c7SVladimir Kondratyev
449f76051c7SVladimir Kondratyev static void
evdev_mt_replay_events(struct evdev_dev * evdev)450f76051c7SVladimir Kondratyev evdev_mt_replay_events(struct evdev_dev *evdev)
451f76051c7SVladimir Kondratyev {
452f76051c7SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
453f76051c7SVladimir Kondratyev int slot, size = 0;
454f76051c7SVladimir Kondratyev
455f76051c7SVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev);
456f76051c7SVladimir Kondratyev
457f76051c7SVladimir Kondratyev FOREACHBIT(mt->match_frame, slot) {
458f76051c7SVladimir Kondratyev if (slot != size)
459f76051c7SVladimir Kondratyev mt->match_slots[size] = mt->match_slots[slot];
460f76051c7SVladimir Kondratyev size++;
461f76051c7SVladimir Kondratyev }
462f76051c7SVladimir Kondratyev evdev_mt_match_frame(evdev, mt->match_slots, size);
463f76051c7SVladimir Kondratyev evdev_mt_send_frame(evdev, mt->match_slots, size);
464f76051c7SVladimir Kondratyev mt->match_slot = 0;
465f76051c7SVladimir Kondratyev mt->match_frame = 0;
466f76051c7SVladimir Kondratyev }
467f76051c7SVladimir Kondratyev
468f76051c7SVladimir Kondratyev union evdev_mt_slot *
evdev_mt_get_match_slots(struct evdev_dev * evdev)469f76051c7SVladimir Kondratyev evdev_mt_get_match_slots(struct evdev_dev *evdev)
470f76051c7SVladimir Kondratyev {
471f76051c7SVladimir Kondratyev return (evdev->ev_mt->match_slots);
472f76051c7SVladimir Kondratyev }
473f76051c7SVladimir Kondratyev
47498a7606bSVladimir Kondratyev int
evdev_mt_get_last_slot(struct evdev_dev * evdev)47598a7606bSVladimir Kondratyev evdev_mt_get_last_slot(struct evdev_dev *evdev)
47698a7606bSVladimir Kondratyev {
47798a7606bSVladimir Kondratyev return (evdev->ev_mt->last_reported_slot);
4782b3f6d66SOleksandr Tymoshenko }
4792b3f6d66SOleksandr Tymoshenko
4802b3f6d66SOleksandr Tymoshenko void
evdev_mt_set_last_slot(struct evdev_dev * evdev,int slot)48198a7606bSVladimir Kondratyev evdev_mt_set_last_slot(struct evdev_dev *evdev, int slot)
4822b3f6d66SOleksandr Tymoshenko {
48398a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
4842b3f6d66SOleksandr Tymoshenko
48598a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
4862b3f6d66SOleksandr Tymoshenko
4872dc7188eSVladimir Kondratyev mt->frame |= 1U << slot;
48898a7606bSVladimir Kondratyev mt->last_reported_slot = slot;
4892b3f6d66SOleksandr Tymoshenko }
4902b3f6d66SOleksandr Tymoshenko
4912b3f6d66SOleksandr Tymoshenko int32_t
evdev_mt_get_value(struct evdev_dev * evdev,int slot,int16_t code)49298a7606bSVladimir Kondratyev evdev_mt_get_value(struct evdev_dev *evdev, int slot, int16_t code)
49398a7606bSVladimir Kondratyev {
49498a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
49598a7606bSVladimir Kondratyev
49698a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
49798a7606bSVladimir Kondratyev
49898a7606bSVladimir Kondratyev return (mt->slots[slot].val[ABS_MT_INDEX(code)]);
49998a7606bSVladimir Kondratyev }
50098a7606bSVladimir Kondratyev
50198a7606bSVladimir Kondratyev void
evdev_mt_set_value(struct evdev_dev * evdev,int slot,int16_t code,int32_t value)50298a7606bSVladimir Kondratyev evdev_mt_set_value(struct evdev_dev *evdev, int slot, int16_t code,
50398a7606bSVladimir Kondratyev int32_t value)
50498a7606bSVladimir Kondratyev {
50598a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
50698a7606bSVladimir Kondratyev
50798a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev));
50898a7606bSVladimir Kondratyev
5092dc7188eSVladimir Kondratyev if (code == ABS_MT_TRACKING_ID) {
5102dc7188eSVladimir Kondratyev if (value != -1)
5112dc7188eSVladimir Kondratyev mt->touches |= 1U << slot;
5122dc7188eSVladimir Kondratyev else
5132dc7188eSVladimir Kondratyev mt->touches &= ~(1U << slot);
5142dc7188eSVladimir Kondratyev }
51598a7606bSVladimir Kondratyev mt->slots[slot].val[ABS_MT_INDEX(code)] = value;
51698a7606bSVladimir Kondratyev }
51798a7606bSVladimir Kondratyev
51898a7606bSVladimir Kondratyev int
evdev_mt_id_to_slot(struct evdev_dev * evdev,int32_t tracking_id)51935bc295bSVladimir Kondratyev evdev_mt_id_to_slot(struct evdev_dev *evdev, int32_t tracking_id)
5202b3f6d66SOleksandr Tymoshenko {
52198a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
5222dc7188eSVladimir Kondratyev int slot;
5232b3f6d66SOleksandr Tymoshenko
524d056693dSVladimir Kondratyev KASSERT(!mt->type_a, ("Not a MT type B protocol"));
525d056693dSVladimir Kondratyev
526f76051c7SVladimir Kondratyev /*
527f76051c7SVladimir Kondratyev * Ignore tracking_id if slot assignment is performed by evdev.
528f76051c7SVladimir Kondratyev * Events are written sequentially to temporary matching buffer.
529f76051c7SVladimir Kondratyev */
530f76051c7SVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK))
531f76051c7SVladimir Kondratyev return (ffc_slot(evdev, mt->match_frame));
532f76051c7SVladimir Kondratyev
5332dc7188eSVladimir Kondratyev FOREACHBIT(mt->touches, slot)
53466bd52f5SVladimir Kondratyev if (mt->tracking_ids[slot] == tracking_id)
5352b3f6d66SOleksandr Tymoshenko return (slot);
5362b3f6d66SOleksandr Tymoshenko /*
5372dc7188eSVladimir Kondratyev * Do not allow allocation of new slot in a place of just
5382dc7188eSVladimir Kondratyev * released one within the same report.
5392b3f6d66SOleksandr Tymoshenko */
5402dc7188eSVladimir Kondratyev return (ffc_slot(evdev, mt->touches | mt->frame));
5412b3f6d66SOleksandr Tymoshenko }
5422b3f6d66SOleksandr Tymoshenko
54366bd52f5SVladimir Kondratyev int32_t
evdev_mt_reassign_id(struct evdev_dev * evdev,int slot,int32_t id)54466bd52f5SVladimir Kondratyev evdev_mt_reassign_id(struct evdev_dev *evdev, int slot, int32_t id)
54566bd52f5SVladimir Kondratyev {
54666bd52f5SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
54766bd52f5SVladimir Kondratyev int32_t nid;
54866bd52f5SVladimir Kondratyev
54966bd52f5SVladimir Kondratyev if (id == -1 || bit_test(evdev->ev_flags, EVDEV_FLAG_MT_KEEPID)) {
55066bd52f5SVladimir Kondratyev mt->tracking_ids[slot] = id;
55166bd52f5SVladimir Kondratyev return (id);
55266bd52f5SVladimir Kondratyev }
55366bd52f5SVladimir Kondratyev
55466bd52f5SVladimir Kondratyev nid = evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID);
55566bd52f5SVladimir Kondratyev if (nid != -1) {
55666bd52f5SVladimir Kondratyev KASSERT(id == mt->tracking_ids[slot],
55766bd52f5SVladimir Kondratyev ("MT-slot tracking id has changed"));
55866bd52f5SVladimir Kondratyev return (nid);
55966bd52f5SVladimir Kondratyev }
56066bd52f5SVladimir Kondratyev
56166bd52f5SVladimir Kondratyev mt->tracking_ids[slot] = id;
56266bd52f5SVladimir Kondratyev again:
56366bd52f5SVladimir Kondratyev nid = mt->tracking_id++;
56466bd52f5SVladimir Kondratyev FOREACHBIT(mt->touches, slot)
56566bd52f5SVladimir Kondratyev if (evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID) == nid)
56666bd52f5SVladimir Kondratyev goto again;
56766bd52f5SVladimir Kondratyev
56866bd52f5SVladimir Kondratyev return (nid);
56966bd52f5SVladimir Kondratyev }
57066bd52f5SVladimir Kondratyev
571127e54deSVladimir Kondratyev static inline int32_t
evdev_mt_normalize(int32_t value,int32_t mtmin,int32_t mtmax,int32_t stmax)572127e54deSVladimir Kondratyev evdev_mt_normalize(int32_t value, int32_t mtmin, int32_t mtmax, int32_t stmax)
573127e54deSVladimir Kondratyev {
574127e54deSVladimir Kondratyev if (stmax != 0 && mtmax != mtmin) {
575127e54deSVladimir Kondratyev value = (value - mtmin) * stmax / (mtmax - mtmin);
576127e54deSVladimir Kondratyev value = MAX(MIN(value, stmax), 0);
577127e54deSVladimir Kondratyev }
578127e54deSVladimir Kondratyev return (value);
579127e54deSVladimir Kondratyev }
580127e54deSVladimir Kondratyev
58135bc295bSVladimir Kondratyev static void
evdev_mt_support_st_compat(struct evdev_dev * evdev)58235bc295bSVladimir Kondratyev evdev_mt_support_st_compat(struct evdev_dev *evdev)
5832b3f6d66SOleksandr Tymoshenko {
584127e54deSVladimir Kondratyev struct input_absinfo *ai;
58598a7606bSVladimir Kondratyev int i;
5862b3f6d66SOleksandr Tymoshenko
5872b3f6d66SOleksandr Tymoshenko if (evdev->ev_absinfo == NULL)
5882b3f6d66SOleksandr Tymoshenko return;
5892b3f6d66SOleksandr Tymoshenko
5902b3f6d66SOleksandr Tymoshenko evdev_support_event(evdev, EV_KEY);
5912b3f6d66SOleksandr Tymoshenko evdev_support_key(evdev, BTN_TOUCH);
5922b3f6d66SOleksandr Tymoshenko
5932b3f6d66SOleksandr Tymoshenko /* Touchscreens should not advertise tap tool capabilities */
5942b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
5952b3f6d66SOleksandr Tymoshenko evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1);
5962b3f6d66SOleksandr Tymoshenko
5972b3f6d66SOleksandr Tymoshenko /* Echo 0-th MT-slot as ST-slot */
598127e54deSVladimir Kondratyev for (i = 0; i < nitems(evdev_mtstmap); i++) {
599127e54deSVladimir Kondratyev if (!bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].mt) ||
600127e54deSVladimir Kondratyev bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].st))
601127e54deSVladimir Kondratyev continue;
602127e54deSVladimir Kondratyev ai = evdev->ev_absinfo + evdev_mtstmap[i].mt;
603127e54deSVladimir Kondratyev evdev->ev_mt->mtst_events |= 1U << i;
604127e54deSVladimir Kondratyev if (evdev_mtstmap[i].max != 0)
605127e54deSVladimir Kondratyev evdev_support_abs(evdev, evdev_mtstmap[i].st,
606314913edSVladimir Kondratyev 0,
607127e54deSVladimir Kondratyev evdev_mtstmap[i].max,
608127e54deSVladimir Kondratyev 0,
609127e54deSVladimir Kondratyev evdev_mt_normalize(
610127e54deSVladimir Kondratyev ai->flat, 0, ai->maximum, evdev_mtstmap[i].max),
611127e54deSVladimir Kondratyev 0);
612127e54deSVladimir Kondratyev else
613127e54deSVladimir Kondratyev evdev_support_abs(evdev, evdev_mtstmap[i].st,
614127e54deSVladimir Kondratyev ai->minimum,
615127e54deSVladimir Kondratyev ai->maximum,
616127e54deSVladimir Kondratyev 0,
617127e54deSVladimir Kondratyev ai->flat,
618127e54deSVladimir Kondratyev ai->resolution);
619127e54deSVladimir Kondratyev }
6202b3f6d66SOleksandr Tymoshenko }
6212b3f6d66SOleksandr Tymoshenko
6222b3f6d66SOleksandr Tymoshenko static void
evdev_mt_send_st_compat(struct evdev_dev * evdev)62398a7606bSVladimir Kondratyev evdev_mt_send_st_compat(struct evdev_dev *evdev)
6242b3f6d66SOleksandr Tymoshenko {
6252dc7188eSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
626fbe17f90SVladimir Kondratyev int nfingers, i, st_slot;
6272b3f6d66SOleksandr Tymoshenko
6282b3f6d66SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev);
6292b3f6d66SOleksandr Tymoshenko
6302dc7188eSVladimir Kondratyev nfingers = bitcount(mt->touches);
6312b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0);
6322b3f6d66SOleksandr Tymoshenko
633fbe17f90SVladimir Kondratyev /* Send first active MT-slot state as single touch report */
634fbe17f90SVladimir Kondratyev st_slot = ffs(mt->touches) - 1;
635fbe17f90SVladimir Kondratyev if (st_slot != -1)
636127e54deSVladimir Kondratyev FOREACHBIT(mt->mtst_events, i)
637127e54deSVladimir Kondratyev evdev_send_event(evdev, EV_ABS, evdev_mtstmap[i].st,
638127e54deSVladimir Kondratyev evdev_mt_normalize(evdev_mt_get_value(evdev,
639127e54deSVladimir Kondratyev st_slot, evdev_mtstmap[i].mt),
640127e54deSVladimir Kondratyev evdev->ev_absinfo[evdev_mtstmap[i].mt].minimum,
641127e54deSVladimir Kondratyev evdev->ev_absinfo[evdev_mtstmap[i].mt].maximum,
642127e54deSVladimir Kondratyev evdev_mtstmap[i].max));
6432b3f6d66SOleksandr Tymoshenko
6442b3f6d66SOleksandr Tymoshenko /* Touchscreens should not report tool taps */
6452b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
6462b3f6d66SOleksandr Tymoshenko evdev_send_nfingers(evdev, nfingers);
6472b3f6d66SOleksandr Tymoshenko
6482b3f6d66SOleksandr Tymoshenko if (nfingers == 0)
6492b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0);
6502b3f6d66SOleksandr Tymoshenko }
6512b3f6d66SOleksandr Tymoshenko
65298a7606bSVladimir Kondratyev static void
evdev_mt_send_autorel(struct evdev_dev * evdev)65398a7606bSVladimir Kondratyev evdev_mt_send_autorel(struct evdev_dev *evdev)
654c736a757SOleksandr Tymoshenko {
65598a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt;
65698a7606bSVladimir Kondratyev int slot;
657c736a757SOleksandr Tymoshenko
658c736a757SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev);
659f76051c7SVladimir Kondratyev KASSERT(mt->match_frame == 0, ("Unmatched events exist"));
660c736a757SOleksandr Tymoshenko
66105936028SVladimir Kondratyev FOREACHBIT(mt->touches & ~mt->frame, slot)
66205936028SVladimir Kondratyev evdev_mt_send_slot(evdev, slot, NULL);
663c736a757SOleksandr Tymoshenko }
66498a7606bSVladimir Kondratyev
66598a7606bSVladimir Kondratyev void
evdev_mt_push_autorel(struct evdev_dev * evdev)66698a7606bSVladimir Kondratyev evdev_mt_push_autorel(struct evdev_dev *evdev)
66798a7606bSVladimir Kondratyev {
66898a7606bSVladimir Kondratyev EVDEV_ENTER(evdev);
66998a7606bSVladimir Kondratyev evdev_mt_send_autorel(evdev);
67098a7606bSVladimir Kondratyev EVDEV_EXIT(evdev);
67198a7606bSVladimir Kondratyev }
672