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 * 262b3f6d66SOleksandr Tymoshenko * $FreeBSD$ 272b3f6d66SOleksandr Tymoshenko */ 284c0a134eSVladimir Kondratyev /*- 294c0a134eSVladimir Kondratyev * Copyright (c) 2015, 2016 Ulf Brosziewski 304c0a134eSVladimir Kondratyev * 314c0a134eSVladimir Kondratyev * Permission to use, copy, modify, and distribute this software for any 324c0a134eSVladimir Kondratyev * purpose with or without fee is hereby granted, provided that the above 334c0a134eSVladimir Kondratyev * copyright notice and this permission notice appear in all copies. 344c0a134eSVladimir Kondratyev * 354c0a134eSVladimir Kondratyev * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 364c0a134eSVladimir Kondratyev * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 374c0a134eSVladimir Kondratyev * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 384c0a134eSVladimir Kondratyev * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 394c0a134eSVladimir Kondratyev * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 404c0a134eSVladimir Kondratyev * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 414c0a134eSVladimir Kondratyev * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 424c0a134eSVladimir 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 602dc7188eSVladimir Kondratyev typedef u_int slotset_t; 612dc7188eSVladimir Kondratyev 622dc7188eSVladimir Kondratyev _Static_assert(MAX_MT_SLOTS < sizeof(slotset_t) * 8, "MAX_MT_SLOTS too big"); 632dc7188eSVladimir Kondratyev 642dc7188eSVladimir Kondratyev #define FOREACHBIT(v, i) \ 652dc7188eSVladimir Kondratyev for ((i) = ffs(v) - 1; (i) != -1; (i) = ffs((v) & (~1 << (i))) - 1) 662dc7188eSVladimir Kondratyev 67127e54deSVladimir Kondratyev struct { 68127e54deSVladimir Kondratyev uint16_t mt; 69127e54deSVladimir Kondratyev uint16_t st; 70127e54deSVladimir Kondratyev int32_t max; 71127e54deSVladimir Kondratyev } static evdev_mtstmap[] = { 72127e54deSVladimir Kondratyev { ABS_MT_POSITION_X, ABS_X, 0 }, 73127e54deSVladimir Kondratyev { ABS_MT_POSITION_Y, ABS_Y, 0 }, 74127e54deSVladimir Kondratyev { ABS_MT_PRESSURE, ABS_PRESSURE, 255 }, 75127e54deSVladimir Kondratyev { ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH, 15 }, 762b3f6d66SOleksandr Tymoshenko }; 772b3f6d66SOleksandr Tymoshenko 782b3f6d66SOleksandr Tymoshenko struct evdev_mt { 7998a7606bSVladimir Kondratyev int last_reported_slot; 8066bd52f5SVladimir Kondratyev uint16_t tracking_id; 8166bd52f5SVladimir Kondratyev int32_t tracking_ids[MAX_MT_SLOTS]; 82d056693dSVladimir Kondratyev bool type_a; 83127e54deSVladimir Kondratyev u_int mtst_events; 842dc7188eSVladimir Kondratyev /* the set of slots with active touches */ 852dc7188eSVladimir Kondratyev slotset_t touches; 862dc7188eSVladimir Kondratyev /* the set of slots with unsynchronized state */ 872dc7188eSVladimir Kondratyev slotset_t frame; 88f76051c7SVladimir Kondratyev /* the set of slots to match with active touches */ 89f76051c7SVladimir Kondratyev slotset_t match_frame; 90f76051c7SVladimir Kondratyev int match_slot; 91f76051c7SVladimir Kondratyev union evdev_mt_slot *match_slots; 924c0a134eSVladimir Kondratyev int *matrix; 9305936028SVladimir Kondratyev union evdev_mt_slot slots[]; 942b3f6d66SOleksandr Tymoshenko }; 952b3f6d66SOleksandr Tymoshenko 9635bc295bSVladimir Kondratyev static void evdev_mt_support_st_compat(struct evdev_dev *); 9798a7606bSVladimir Kondratyev static void evdev_mt_send_st_compat(struct evdev_dev *); 9898a7606bSVladimir Kondratyev static void evdev_mt_send_autorel(struct evdev_dev *); 99f76051c7SVladimir Kondratyev static void evdev_mt_replay_events(struct evdev_dev *); 10098a7606bSVladimir Kondratyev 1012dc7188eSVladimir Kondratyev static inline int 1022dc7188eSVladimir Kondratyev ffc_slot(struct evdev_dev *evdev, slotset_t slots) 1032dc7188eSVladimir Kondratyev { 104*d99c87c8SJohn Baldwin return (ffs(~slots & ((2U << MAXIMAL_MT_SLOT(evdev)) - 1)) - 1); 1052dc7188eSVladimir Kondratyev } 1062dc7188eSVladimir Kondratyev 1072b3f6d66SOleksandr Tymoshenko void 1082b3f6d66SOleksandr Tymoshenko evdev_mt_init(struct evdev_dev *evdev) 1092b3f6d66SOleksandr Tymoshenko { 1104c0a134eSVladimir Kondratyev struct evdev_mt *mt; 1114c0a134eSVladimir Kondratyev size_t size = offsetof(struct evdev_mt, slots); 11298a7606bSVladimir Kondratyev int slot, slots; 113d056693dSVladimir Kondratyev bool type_a; 114d056693dSVladimir Kondratyev 115d056693dSVladimir Kondratyev type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT); 116d056693dSVladimir Kondratyev if (type_a) { 117d056693dSVladimir Kondratyev /* Add events produced by MT type A to type B converter */ 118d056693dSVladimir Kondratyev evdev_support_abs(evdev, 119d056693dSVladimir Kondratyev ABS_MT_SLOT, 0, MAX_MT_SLOTS - 1, 0, 0, 0); 120d056693dSVladimir Kondratyev evdev_support_abs(evdev, 121d056693dSVladimir Kondratyev ABS_MT_TRACKING_ID, -1, MAX_MT_SLOTS - 1, 0, 0, 0); 122d056693dSVladimir Kondratyev } 1232b3f6d66SOleksandr Tymoshenko 1242b3f6d66SOleksandr Tymoshenko slots = MAXIMAL_MT_SLOT(evdev) + 1; 1254c0a134eSVladimir Kondratyev size += sizeof(mt->slots[0]) * slots; 1264c0a134eSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) { 127f76051c7SVladimir Kondratyev size += sizeof(mt->match_slots[0]) * slots; 1284c0a134eSVladimir Kondratyev size += sizeof(mt->matrix[0]) * (slots + 6) * slots; 1294c0a134eSVladimir Kondratyev } 1302b3f6d66SOleksandr Tymoshenko 1314c0a134eSVladimir Kondratyev mt = malloc(size, M_EVDEV, M_WAITOK | M_ZERO); 1324c0a134eSVladimir Kondratyev evdev->ev_mt = mt; 133d056693dSVladimir Kondratyev mt->type_a = type_a; 1344c0a134eSVladimir Kondratyev 1354c0a134eSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) { 136f76051c7SVladimir Kondratyev mt->match_slots = mt->slots + slots; 137f76051c7SVladimir Kondratyev mt->matrix = (int *)(mt->match_slots + slots); 1384c0a134eSVladimir Kondratyev } 1392b3f6d66SOleksandr Tymoshenko 1402b3f6d66SOleksandr Tymoshenko /* Initialize multitouch protocol type B states */ 1412dc7188eSVladimir Kondratyev for (slot = 0; slot < slots; slot++) 142f76051c7SVladimir Kondratyev mt->slots[slot].id = -1; 1432b3f6d66SOleksandr Tymoshenko 14466bd52f5SVladimir Kondratyev if (!bit_test(evdev->ev_flags, EVDEV_FLAG_MT_KEEPID)) 14566bd52f5SVladimir Kondratyev evdev_support_abs(evdev, 14666bd52f5SVladimir Kondratyev ABS_MT_TRACKING_ID, -1, UINT16_MAX, 0, 0, 0); 1472b3f6d66SOleksandr Tymoshenko if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) 14835bc295bSVladimir Kondratyev evdev_mt_support_st_compat(evdev); 1492b3f6d66SOleksandr Tymoshenko } 1502b3f6d66SOleksandr Tymoshenko 1512b3f6d66SOleksandr Tymoshenko void 1522b3f6d66SOleksandr Tymoshenko evdev_mt_free(struct evdev_dev *evdev) 1532b3f6d66SOleksandr Tymoshenko { 1542b3f6d66SOleksandr Tymoshenko free(evdev->ev_mt, M_EVDEV); 1552b3f6d66SOleksandr Tymoshenko } 1562b3f6d66SOleksandr Tymoshenko 15798a7606bSVladimir Kondratyev void 15898a7606bSVladimir Kondratyev evdev_mt_sync_frame(struct evdev_dev *evdev) 1592b3f6d66SOleksandr Tymoshenko { 160f76051c7SVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) 161f76051c7SVladimir Kondratyev evdev_mt_replay_events(evdev); 16298a7606bSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL)) 16398a7606bSVladimir Kondratyev evdev_mt_send_autorel(evdev); 16498a7606bSVladimir Kondratyev if (evdev->ev_report_opened && 16598a7606bSVladimir Kondratyev bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) 16698a7606bSVladimir Kondratyev evdev_mt_send_st_compat(evdev); 1672dc7188eSVladimir Kondratyev evdev->ev_mt->frame = 0; 16898a7606bSVladimir Kondratyev } 1692b3f6d66SOleksandr Tymoshenko 17005936028SVladimir Kondratyev static void 17105936028SVladimir Kondratyev evdev_mt_send_slot(struct evdev_dev *evdev, int slot, 17205936028SVladimir Kondratyev union evdev_mt_slot *state) 17305936028SVladimir Kondratyev { 17405936028SVladimir Kondratyev int i; 17505936028SVladimir Kondratyev bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT); 17605936028SVladimir Kondratyev 17705936028SVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev); 17805936028SVladimir Kondratyev MPASS(type_a || (slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev))); 17905936028SVladimir Kondratyev MPASS(!type_a || state != NULL); 18005936028SVladimir Kondratyev 18105936028SVladimir Kondratyev if (!type_a) { 18205936028SVladimir Kondratyev evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot); 18305936028SVladimir Kondratyev if (state == NULL) { 18405936028SVladimir Kondratyev evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID, -1); 18505936028SVladimir Kondratyev return; 18605936028SVladimir Kondratyev } 18705936028SVladimir Kondratyev } 18805936028SVladimir Kondratyev bit_foreach_at(evdev->ev_abs_flags, ABS_MT_FIRST, ABS_MT_LAST + 1, i) 18905936028SVladimir Kondratyev evdev_send_event(evdev, EV_ABS, i, 19005936028SVladimir Kondratyev state->val[ABS_MT_INDEX(i)]); 19105936028SVladimir Kondratyev if (type_a) 19205936028SVladimir Kondratyev evdev_send_event(evdev, EV_SYN, SYN_MT_REPORT, 1); 19305936028SVladimir Kondratyev } 19405936028SVladimir Kondratyev 19505936028SVladimir Kondratyev int 19605936028SVladimir Kondratyev evdev_mt_push_slot(struct evdev_dev *evdev, int slot, 19705936028SVladimir Kondratyev union evdev_mt_slot *state) 19805936028SVladimir Kondratyev { 199f76051c7SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 20005936028SVladimir Kondratyev bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT); 20105936028SVladimir Kondratyev 202d056693dSVladimir Kondratyev if ((type_a || (mt != NULL && mt->type_a)) && state == NULL) 20305936028SVladimir Kondratyev return (EINVAL); 20405936028SVladimir Kondratyev if (!type_a && (slot < 0 || slot > MAXIMAL_MT_SLOT(evdev))) 20505936028SVladimir Kondratyev return (EINVAL); 20605936028SVladimir Kondratyev 20705936028SVladimir Kondratyev EVDEV_ENTER(evdev); 208d056693dSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK) && mt->type_a) { 209d056693dSVladimir Kondratyev mt->match_slots[mt->match_slot] = *state; 210d056693dSVladimir Kondratyev evdev_mt_record_event(evdev, EV_SYN, SYN_MT_REPORT, 1); 211d056693dSVladimir Kondratyev } else if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) { 212f76051c7SVladimir Kondratyev evdev_mt_record_event(evdev, EV_ABS, ABS_MT_SLOT, slot); 213f76051c7SVladimir Kondratyev if (state != NULL) 214f76051c7SVladimir Kondratyev mt->match_slots[mt->match_slot] = *state; 215f76051c7SVladimir Kondratyev else 216f76051c7SVladimir Kondratyev evdev_mt_record_event(evdev, EV_ABS, 217f76051c7SVladimir Kondratyev ABS_MT_TRACKING_ID, -1); 218f76051c7SVladimir Kondratyev } else 21905936028SVladimir Kondratyev evdev_mt_send_slot(evdev, slot, state); 22005936028SVladimir Kondratyev EVDEV_EXIT(evdev); 22105936028SVladimir Kondratyev 22205936028SVladimir Kondratyev return (0); 22305936028SVladimir Kondratyev } 22405936028SVladimir Kondratyev 2254c0a134eSVladimir Kondratyev /* 2264c0a134eSVladimir Kondratyev * Find a minimum-weight matching for an m-by-n matrix. 2274c0a134eSVladimir Kondratyev * 2284c0a134eSVladimir Kondratyev * m must be greater than or equal to n. The size of the buffer must be 2294c0a134eSVladimir Kondratyev * at least 3m + 3n. 2304c0a134eSVladimir Kondratyev * 2314c0a134eSVladimir Kondratyev * On return, the first m elements of the buffer contain the row-to- 2324c0a134eSVladimir Kondratyev * column mappings, i.e., buffer[i] is the column index for row i, or -1 2334c0a134eSVladimir Kondratyev * if there is no assignment for that row (which may happen if n < m). 2344c0a134eSVladimir Kondratyev * 2354c0a134eSVladimir Kondratyev * Wrong results because of overflows will not occur with input values 2364c0a134eSVladimir Kondratyev * in the range of 0 to INT_MAX / 2 inclusive. 2374c0a134eSVladimir Kondratyev * 2384c0a134eSVladimir Kondratyev * The function applies the Dinic-Kronrod algorithm. It is not modern or 2394c0a134eSVladimir Kondratyev * popular, but it seems to be a good choice for small matrices at least. 2404c0a134eSVladimir Kondratyev * The original form of the algorithm is modified as follows: There is no 2414c0a134eSVladimir Kondratyev * initial search for row minima, the initial assignments are in a 2424c0a134eSVladimir Kondratyev * "virtual" column with the index -1 and zero values. This permits inputs 2434c0a134eSVladimir Kondratyev * with n < m, and it simplifies the reassignments. 2444c0a134eSVladimir Kondratyev */ 2454c0a134eSVladimir Kondratyev static void 2464c0a134eSVladimir Kondratyev evdev_mt_matching(int *matrix, int m, int n, int *buffer) 2474c0a134eSVladimir Kondratyev { 2484c0a134eSVladimir Kondratyev int i, j, k, d, e, row, col, delta; 2494c0a134eSVladimir Kondratyev int *p; 2504c0a134eSVladimir Kondratyev int *r2c = buffer; /* row-to-column assignments */ 2514c0a134eSVladimir Kondratyev int *red = r2c + m; /* reduced values of the assignments */ 2524c0a134eSVladimir Kondratyev int *mc = red + m; /* row-wise minimal elements of cs */ 2534c0a134eSVladimir Kondratyev int *cs = mc + m; /* the column set */ 2544c0a134eSVladimir Kondratyev int *c2r = cs + n; /* column-to-row assignments in cs */ 2554c0a134eSVladimir Kondratyev int *cd = c2r + n; /* column deltas (reduction) */ 2564c0a134eSVladimir Kondratyev 2574c0a134eSVladimir Kondratyev for (p = r2c; p < red; *p++ = -1) {} 2584c0a134eSVladimir Kondratyev for (; p < mc; *p++ = 0) {} 2594c0a134eSVladimir Kondratyev for (col = 0; col < n; col++) { 2604c0a134eSVladimir Kondratyev delta = INT_MAX; 2614c0a134eSVladimir Kondratyev for (i = 0, p = matrix + col; i < m; i++, p += n) { 2624c0a134eSVladimir Kondratyev d = *p - red[i]; 2634c0a134eSVladimir Kondratyev if (d < delta || (d == delta && r2c[i] < 0)) { 2644c0a134eSVladimir Kondratyev delta = d; 2654c0a134eSVladimir Kondratyev row = i; 2664c0a134eSVladimir Kondratyev } 2674c0a134eSVladimir Kondratyev } 2684c0a134eSVladimir Kondratyev cd[col] = delta; 2694c0a134eSVladimir Kondratyev if (r2c[row] < 0) { 2704c0a134eSVladimir Kondratyev r2c[row] = col; 2714c0a134eSVladimir Kondratyev continue; 2724c0a134eSVladimir Kondratyev } 2734c0a134eSVladimir Kondratyev for (p = mc; p < cs; *p++ = col) {} 2744c0a134eSVladimir Kondratyev for (k = 0; (j = r2c[row]) >= 0;) { 2754c0a134eSVladimir Kondratyev cs[k++] = j; 2764c0a134eSVladimir Kondratyev c2r[j] = row; 2774c0a134eSVladimir Kondratyev mc[row] -= n; 2784c0a134eSVladimir Kondratyev delta = INT_MAX; 2794c0a134eSVladimir Kondratyev for (i = 0, p = matrix; i < m; i++, p += n) 2804c0a134eSVladimir Kondratyev if (mc[i] >= 0) { 2814c0a134eSVladimir Kondratyev d = p[mc[i]] - cd[mc[i]]; 2824c0a134eSVladimir Kondratyev e = p[j] - cd[j]; 2834c0a134eSVladimir Kondratyev if (e < d) { 2844c0a134eSVladimir Kondratyev d = e; 2854c0a134eSVladimir Kondratyev mc[i] = j; 2864c0a134eSVladimir Kondratyev } 2874c0a134eSVladimir Kondratyev d -= red[i]; 2884c0a134eSVladimir Kondratyev if (d < delta || (d == delta 2894c0a134eSVladimir Kondratyev && r2c[i] < 0)) { 2904c0a134eSVladimir Kondratyev delta = d; 2914c0a134eSVladimir Kondratyev row = i; 2924c0a134eSVladimir Kondratyev } 2934c0a134eSVladimir Kondratyev } 2944c0a134eSVladimir Kondratyev cd[col] += delta; 2954c0a134eSVladimir Kondratyev for (i = 0; i < k; i++) { 2964c0a134eSVladimir Kondratyev cd[cs[i]] += delta; 2974c0a134eSVladimir Kondratyev red[c2r[cs[i]]] -= delta; 2984c0a134eSVladimir Kondratyev } 2994c0a134eSVladimir Kondratyev } 3004c0a134eSVladimir Kondratyev for (j = mc[row]; (r2c[row] = j) != col;) { 3014c0a134eSVladimir Kondratyev row = c2r[j]; 3024c0a134eSVladimir Kondratyev j = mc[row] + n; 3034c0a134eSVladimir Kondratyev } 3044c0a134eSVladimir Kondratyev } 3054c0a134eSVladimir Kondratyev } 3064c0a134eSVladimir Kondratyev 3074c0a134eSVladimir Kondratyev /* 3084c0a134eSVladimir Kondratyev * Assign tracking IDs to the points in the pt array. The tracking ID 3094c0a134eSVladimir Kondratyev * assignment pairs the points with points of the previous frame in 3104c0a134eSVladimir Kondratyev * such a way that the sum of the squared distances is minimal. Using 3114c0a134eSVladimir Kondratyev * squares instead of simple distances favours assignments with more uniform 3124c0a134eSVladimir Kondratyev * distances, and it is faster. 3134c0a134eSVladimir Kondratyev * Set tracking id to -1 for unassigned (new) points. 3144c0a134eSVladimir Kondratyev */ 3154c0a134eSVladimir Kondratyev void 3164c0a134eSVladimir Kondratyev evdev_mt_match_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, 3174c0a134eSVladimir Kondratyev int size) 3184c0a134eSVladimir Kondratyev { 3194c0a134eSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 3204c0a134eSVladimir Kondratyev int i, j, m, n, dx, dy, slot, num_touches; 3214c0a134eSVladimir Kondratyev int *p, *r2c, *c2r; 3224c0a134eSVladimir Kondratyev 3234c0a134eSVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev); 3244c0a134eSVladimir Kondratyev MPASS(mt->matrix != NULL); 3254c0a134eSVladimir Kondratyev MPASS(size >= 0 && size <= MAXIMAL_MT_SLOT(evdev) + 1); 3264c0a134eSVladimir Kondratyev 3274c0a134eSVladimir Kondratyev if (size == 0) 3284c0a134eSVladimir Kondratyev return; 3294c0a134eSVladimir Kondratyev 3304c0a134eSVladimir Kondratyev p = mt->matrix; 3314c0a134eSVladimir Kondratyev num_touches = bitcount(mt->touches); 3324c0a134eSVladimir Kondratyev if (num_touches >= size) { 3334c0a134eSVladimir Kondratyev FOREACHBIT(mt->touches, slot) 3344c0a134eSVladimir Kondratyev for (i = 0; i < size; i++) { 3354c0a134eSVladimir Kondratyev dx = pt[i].x - mt->slots[slot].x; 3364c0a134eSVladimir Kondratyev dy = pt[i].y - mt->slots[slot].y; 3374c0a134eSVladimir Kondratyev *p++ = dx * dx + dy * dy; 3384c0a134eSVladimir Kondratyev } 3394c0a134eSVladimir Kondratyev m = num_touches; 3404c0a134eSVladimir Kondratyev n = size; 3414c0a134eSVladimir Kondratyev } else { 3424c0a134eSVladimir Kondratyev for (i = 0; i < size; i++) 3434c0a134eSVladimir Kondratyev FOREACHBIT(mt->touches, slot) { 3444c0a134eSVladimir Kondratyev dx = pt[i].x - mt->slots[slot].x; 3454c0a134eSVladimir Kondratyev dy = pt[i].y - mt->slots[slot].y; 3464c0a134eSVladimir Kondratyev *p++ = dx * dx + dy * dy; 3474c0a134eSVladimir Kondratyev } 3484c0a134eSVladimir Kondratyev m = size; 3494c0a134eSVladimir Kondratyev n = num_touches; 3504c0a134eSVladimir Kondratyev } 3514c0a134eSVladimir Kondratyev evdev_mt_matching(mt->matrix, m, n, p); 3524c0a134eSVladimir Kondratyev 3534c0a134eSVladimir Kondratyev r2c = p; 3544c0a134eSVladimir Kondratyev c2r = p + m; 3554c0a134eSVladimir Kondratyev for (i = 0; i < m; i++) 3564c0a134eSVladimir Kondratyev if ((j = r2c[i]) >= 0) 3574c0a134eSVladimir Kondratyev c2r[j] = i; 3584c0a134eSVladimir Kondratyev 3594c0a134eSVladimir Kondratyev p = (n == size ? c2r : r2c); 3604c0a134eSVladimir Kondratyev for (i = 0; i < size; i++) 3614c0a134eSVladimir Kondratyev if (*p++ < 0) 3624c0a134eSVladimir Kondratyev pt[i].id = -1; 3634c0a134eSVladimir Kondratyev 3644c0a134eSVladimir Kondratyev p = (n == size ? r2c : c2r); 3654c0a134eSVladimir Kondratyev FOREACHBIT(mt->touches, slot) 3664c0a134eSVladimir Kondratyev if ((i = *p++) >= 0) 3674c0a134eSVladimir Kondratyev pt[i].id = mt->tracking_ids[slot]; 3684c0a134eSVladimir Kondratyev } 3694c0a134eSVladimir Kondratyev 3704c0a134eSVladimir Kondratyev static void 3714c0a134eSVladimir Kondratyev evdev_mt_send_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, int size) 3724c0a134eSVladimir Kondratyev { 3734c0a134eSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 3744c0a134eSVladimir Kondratyev union evdev_mt_slot *slot; 3754c0a134eSVladimir Kondratyev 3764c0a134eSVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev); 3774c0a134eSVladimir Kondratyev MPASS(size >= 0 && size <= MAXIMAL_MT_SLOT(evdev) + 1); 3784c0a134eSVladimir Kondratyev 3794c0a134eSVladimir Kondratyev /* 3804c0a134eSVladimir Kondratyev * While MT-matching assign tracking IDs of new contacts to be equal 3814c0a134eSVladimir Kondratyev * to a slot number to make things simpler. 3824c0a134eSVladimir Kondratyev */ 3834c0a134eSVladimir Kondratyev for (slot = pt; slot < pt + size; slot++) { 3844c0a134eSVladimir Kondratyev if (slot->id < 0) 3854c0a134eSVladimir Kondratyev slot->id = ffc_slot(evdev, mt->touches | mt->frame); 3864c0a134eSVladimir Kondratyev if (slot->id >= 0) 3874c0a134eSVladimir Kondratyev evdev_mt_send_slot(evdev, slot->id, slot); 3884c0a134eSVladimir Kondratyev } 3894c0a134eSVladimir Kondratyev } 3904c0a134eSVladimir Kondratyev 3914c0a134eSVladimir Kondratyev int 3924c0a134eSVladimir Kondratyev evdev_mt_push_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, int size) 3934c0a134eSVladimir Kondratyev { 3944c0a134eSVladimir Kondratyev if (size < 0 || size > MAXIMAL_MT_SLOT(evdev) + 1) 3954c0a134eSVladimir Kondratyev return (EINVAL); 3964c0a134eSVladimir Kondratyev 3974c0a134eSVladimir Kondratyev EVDEV_ENTER(evdev); 3984c0a134eSVladimir Kondratyev evdev_mt_send_frame(evdev, pt, size); 3994c0a134eSVladimir Kondratyev EVDEV_EXIT(evdev); 4004c0a134eSVladimir Kondratyev 4014c0a134eSVladimir Kondratyev return (0); 4024c0a134eSVladimir Kondratyev } 4034c0a134eSVladimir Kondratyev 404f76051c7SVladimir Kondratyev bool 405f76051c7SVladimir Kondratyev evdev_mt_record_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, 406f76051c7SVladimir Kondratyev int32_t value) 407f76051c7SVladimir Kondratyev { 408f76051c7SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 409f76051c7SVladimir Kondratyev 410f76051c7SVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev); 411f76051c7SVladimir Kondratyev 412f76051c7SVladimir Kondratyev switch (type) { 413d056693dSVladimir Kondratyev case EV_SYN: 414d056693dSVladimir Kondratyev if (code == SYN_MT_REPORT) { 415d056693dSVladimir Kondratyev /* MT protocol type A support */ 416d056693dSVladimir Kondratyev KASSERT(mt->type_a, ("Not a MT type A protocol")); 417d056693dSVladimir Kondratyev mt->match_frame |= 1U << mt->match_slot; 418d056693dSVladimir Kondratyev mt->match_slot++; 419d056693dSVladimir Kondratyev return (true); 420d056693dSVladimir Kondratyev } 421d056693dSVladimir Kondratyev break; 422f76051c7SVladimir Kondratyev case EV_ABS: 423f76051c7SVladimir Kondratyev if (code == ABS_MT_SLOT) { 424f76051c7SVladimir Kondratyev /* MT protocol type B support */ 425d056693dSVladimir Kondratyev KASSERT(!mt->type_a, ("Not a MT type B protocol")); 426f76051c7SVladimir Kondratyev KASSERT(value >= 0, ("Negative slot number")); 427f76051c7SVladimir Kondratyev mt->match_slot = value; 428f76051c7SVladimir Kondratyev mt->match_frame |= 1U << mt->match_slot; 429f76051c7SVladimir Kondratyev return (true); 430f76051c7SVladimir Kondratyev } else if (code == ABS_MT_TRACKING_ID) { 431d056693dSVladimir Kondratyev KASSERT(!mt->type_a, ("Not a MT type B protocol")); 432f76051c7SVladimir Kondratyev if (value == -1) 433f76051c7SVladimir Kondratyev mt->match_frame &= ~(1U << mt->match_slot); 434f76051c7SVladimir Kondratyev return (true); 435f76051c7SVladimir Kondratyev } else if (ABS_IS_MT(code)) { 436f76051c7SVladimir Kondratyev KASSERT(mt->match_slot >= 0, ("Negative slot")); 437f76051c7SVladimir Kondratyev KASSERT(mt->match_slot <= MAXIMAL_MT_SLOT(evdev), 438f76051c7SVladimir Kondratyev ("Slot number too big")); 439f76051c7SVladimir Kondratyev mt->match_slots[mt->match_slot]. 440f76051c7SVladimir Kondratyev val[ABS_MT_INDEX(code)] = value; 441f76051c7SVladimir Kondratyev return (true); 442f76051c7SVladimir Kondratyev } 443f76051c7SVladimir Kondratyev break; 444f76051c7SVladimir Kondratyev default: 445f76051c7SVladimir Kondratyev break; 446f76051c7SVladimir Kondratyev } 447f76051c7SVladimir Kondratyev 448f76051c7SVladimir Kondratyev return (false); 449f76051c7SVladimir Kondratyev } 450f76051c7SVladimir Kondratyev 451f76051c7SVladimir Kondratyev static void 452f76051c7SVladimir Kondratyev evdev_mt_replay_events(struct evdev_dev *evdev) 453f76051c7SVladimir Kondratyev { 454f76051c7SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 455f76051c7SVladimir Kondratyev int slot, size = 0; 456f76051c7SVladimir Kondratyev 457f76051c7SVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev); 458f76051c7SVladimir Kondratyev 459f76051c7SVladimir Kondratyev FOREACHBIT(mt->match_frame, slot) { 460f76051c7SVladimir Kondratyev if (slot != size) 461f76051c7SVladimir Kondratyev mt->match_slots[size] = mt->match_slots[slot]; 462f76051c7SVladimir Kondratyev size++; 463f76051c7SVladimir Kondratyev } 464f76051c7SVladimir Kondratyev evdev_mt_match_frame(evdev, mt->match_slots, size); 465f76051c7SVladimir Kondratyev evdev_mt_send_frame(evdev, mt->match_slots, size); 466f76051c7SVladimir Kondratyev mt->match_slot = 0; 467f76051c7SVladimir Kondratyev mt->match_frame = 0; 468f76051c7SVladimir Kondratyev } 469f76051c7SVladimir Kondratyev 470f76051c7SVladimir Kondratyev union evdev_mt_slot * 471f76051c7SVladimir Kondratyev evdev_mt_get_match_slots(struct evdev_dev *evdev) 472f76051c7SVladimir Kondratyev { 473f76051c7SVladimir Kondratyev return (evdev->ev_mt->match_slots); 474f76051c7SVladimir Kondratyev } 475f76051c7SVladimir Kondratyev 47698a7606bSVladimir Kondratyev int 47798a7606bSVladimir Kondratyev evdev_mt_get_last_slot(struct evdev_dev *evdev) 47898a7606bSVladimir Kondratyev { 47998a7606bSVladimir Kondratyev return (evdev->ev_mt->last_reported_slot); 4802b3f6d66SOleksandr Tymoshenko } 4812b3f6d66SOleksandr Tymoshenko 4822b3f6d66SOleksandr Tymoshenko void 48398a7606bSVladimir Kondratyev evdev_mt_set_last_slot(struct evdev_dev *evdev, int slot) 4842b3f6d66SOleksandr Tymoshenko { 48598a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 4862b3f6d66SOleksandr Tymoshenko 48798a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 4882b3f6d66SOleksandr Tymoshenko 4892dc7188eSVladimir Kondratyev mt->frame |= 1U << slot; 49098a7606bSVladimir Kondratyev mt->last_reported_slot = slot; 4912b3f6d66SOleksandr Tymoshenko } 4922b3f6d66SOleksandr Tymoshenko 4932b3f6d66SOleksandr Tymoshenko int32_t 49498a7606bSVladimir Kondratyev evdev_mt_get_value(struct evdev_dev *evdev, int slot, int16_t code) 49598a7606bSVladimir Kondratyev { 49698a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 49798a7606bSVladimir Kondratyev 49898a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 49998a7606bSVladimir Kondratyev 50098a7606bSVladimir Kondratyev return (mt->slots[slot].val[ABS_MT_INDEX(code)]); 50198a7606bSVladimir Kondratyev } 50298a7606bSVladimir Kondratyev 50398a7606bSVladimir Kondratyev void 50498a7606bSVladimir Kondratyev evdev_mt_set_value(struct evdev_dev *evdev, int slot, int16_t code, 50598a7606bSVladimir Kondratyev int32_t value) 50698a7606bSVladimir Kondratyev { 50798a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 50898a7606bSVladimir Kondratyev 50998a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 51098a7606bSVladimir Kondratyev 5112dc7188eSVladimir Kondratyev if (code == ABS_MT_TRACKING_ID) { 5122dc7188eSVladimir Kondratyev if (value != -1) 5132dc7188eSVladimir Kondratyev mt->touches |= 1U << slot; 5142dc7188eSVladimir Kondratyev else 5152dc7188eSVladimir Kondratyev mt->touches &= ~(1U << slot); 5162dc7188eSVladimir Kondratyev } 51798a7606bSVladimir Kondratyev mt->slots[slot].val[ABS_MT_INDEX(code)] = value; 51898a7606bSVladimir Kondratyev } 51998a7606bSVladimir Kondratyev 52098a7606bSVladimir Kondratyev int 52135bc295bSVladimir Kondratyev evdev_mt_id_to_slot(struct evdev_dev *evdev, int32_t tracking_id) 5222b3f6d66SOleksandr Tymoshenko { 52398a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 5242dc7188eSVladimir Kondratyev int slot; 5252b3f6d66SOleksandr Tymoshenko 526d056693dSVladimir Kondratyev KASSERT(!mt->type_a, ("Not a MT type B protocol")); 527d056693dSVladimir Kondratyev 528f76051c7SVladimir Kondratyev /* 529f76051c7SVladimir Kondratyev * Ignore tracking_id if slot assignment is performed by evdev. 530f76051c7SVladimir Kondratyev * Events are written sequentially to temporary matching buffer. 531f76051c7SVladimir Kondratyev */ 532f76051c7SVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) 533f76051c7SVladimir Kondratyev return (ffc_slot(evdev, mt->match_frame)); 534f76051c7SVladimir Kondratyev 5352dc7188eSVladimir Kondratyev FOREACHBIT(mt->touches, slot) 53666bd52f5SVladimir Kondratyev if (mt->tracking_ids[slot] == tracking_id) 5372b3f6d66SOleksandr Tymoshenko return (slot); 5382b3f6d66SOleksandr Tymoshenko /* 5392dc7188eSVladimir Kondratyev * Do not allow allocation of new slot in a place of just 5402dc7188eSVladimir Kondratyev * released one within the same report. 5412b3f6d66SOleksandr Tymoshenko */ 5422dc7188eSVladimir Kondratyev return (ffc_slot(evdev, mt->touches | mt->frame)); 5432b3f6d66SOleksandr Tymoshenko } 5442b3f6d66SOleksandr Tymoshenko 54566bd52f5SVladimir Kondratyev int32_t 54666bd52f5SVladimir Kondratyev evdev_mt_reassign_id(struct evdev_dev *evdev, int slot, int32_t id) 54766bd52f5SVladimir Kondratyev { 54866bd52f5SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 54966bd52f5SVladimir Kondratyev int32_t nid; 55066bd52f5SVladimir Kondratyev 55166bd52f5SVladimir Kondratyev if (id == -1 || bit_test(evdev->ev_flags, EVDEV_FLAG_MT_KEEPID)) { 55266bd52f5SVladimir Kondratyev mt->tracking_ids[slot] = id; 55366bd52f5SVladimir Kondratyev return (id); 55466bd52f5SVladimir Kondratyev } 55566bd52f5SVladimir Kondratyev 55666bd52f5SVladimir Kondratyev nid = evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID); 55766bd52f5SVladimir Kondratyev if (nid != -1) { 55866bd52f5SVladimir Kondratyev KASSERT(id == mt->tracking_ids[slot], 55966bd52f5SVladimir Kondratyev ("MT-slot tracking id has changed")); 56066bd52f5SVladimir Kondratyev return (nid); 56166bd52f5SVladimir Kondratyev } 56266bd52f5SVladimir Kondratyev 56366bd52f5SVladimir Kondratyev mt->tracking_ids[slot] = id; 56466bd52f5SVladimir Kondratyev again: 56566bd52f5SVladimir Kondratyev nid = mt->tracking_id++; 56666bd52f5SVladimir Kondratyev FOREACHBIT(mt->touches, slot) 56766bd52f5SVladimir Kondratyev if (evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID) == nid) 56866bd52f5SVladimir Kondratyev goto again; 56966bd52f5SVladimir Kondratyev 57066bd52f5SVladimir Kondratyev return (nid); 57166bd52f5SVladimir Kondratyev } 57266bd52f5SVladimir Kondratyev 573127e54deSVladimir Kondratyev static inline int32_t 574127e54deSVladimir Kondratyev evdev_mt_normalize(int32_t value, int32_t mtmin, int32_t mtmax, int32_t stmax) 575127e54deSVladimir Kondratyev { 576127e54deSVladimir Kondratyev if (stmax != 0 && mtmax != mtmin) { 577127e54deSVladimir Kondratyev value = (value - mtmin) * stmax / (mtmax - mtmin); 578127e54deSVladimir Kondratyev value = MAX(MIN(value, stmax), 0); 579127e54deSVladimir Kondratyev } 580127e54deSVladimir Kondratyev return (value); 581127e54deSVladimir Kondratyev } 582127e54deSVladimir Kondratyev 58335bc295bSVladimir Kondratyev static void 58435bc295bSVladimir Kondratyev evdev_mt_support_st_compat(struct evdev_dev *evdev) 5852b3f6d66SOleksandr Tymoshenko { 586127e54deSVladimir Kondratyev struct input_absinfo *ai; 58798a7606bSVladimir Kondratyev int i; 5882b3f6d66SOleksandr Tymoshenko 5892b3f6d66SOleksandr Tymoshenko if (evdev->ev_absinfo == NULL) 5902b3f6d66SOleksandr Tymoshenko return; 5912b3f6d66SOleksandr Tymoshenko 5922b3f6d66SOleksandr Tymoshenko evdev_support_event(evdev, EV_KEY); 5932b3f6d66SOleksandr Tymoshenko evdev_support_key(evdev, BTN_TOUCH); 5942b3f6d66SOleksandr Tymoshenko 5952b3f6d66SOleksandr Tymoshenko /* Touchscreens should not advertise tap tool capabilities */ 5962b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 5972b3f6d66SOleksandr Tymoshenko evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1); 5982b3f6d66SOleksandr Tymoshenko 5992b3f6d66SOleksandr Tymoshenko /* Echo 0-th MT-slot as ST-slot */ 600127e54deSVladimir Kondratyev for (i = 0; i < nitems(evdev_mtstmap); i++) { 601127e54deSVladimir Kondratyev if (!bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].mt) || 602127e54deSVladimir Kondratyev bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].st)) 603127e54deSVladimir Kondratyev continue; 604127e54deSVladimir Kondratyev ai = evdev->ev_absinfo + evdev_mtstmap[i].mt; 605127e54deSVladimir Kondratyev evdev->ev_mt->mtst_events |= 1U << i; 606127e54deSVladimir Kondratyev if (evdev_mtstmap[i].max != 0) 607127e54deSVladimir Kondratyev evdev_support_abs(evdev, evdev_mtstmap[i].st, 608314913edSVladimir Kondratyev 0, 609127e54deSVladimir Kondratyev evdev_mtstmap[i].max, 610127e54deSVladimir Kondratyev 0, 611127e54deSVladimir Kondratyev evdev_mt_normalize( 612127e54deSVladimir Kondratyev ai->flat, 0, ai->maximum, evdev_mtstmap[i].max), 613127e54deSVladimir Kondratyev 0); 614127e54deSVladimir Kondratyev else 615127e54deSVladimir Kondratyev evdev_support_abs(evdev, evdev_mtstmap[i].st, 616127e54deSVladimir Kondratyev ai->minimum, 617127e54deSVladimir Kondratyev ai->maximum, 618127e54deSVladimir Kondratyev 0, 619127e54deSVladimir Kondratyev ai->flat, 620127e54deSVladimir Kondratyev ai->resolution); 621127e54deSVladimir Kondratyev } 6222b3f6d66SOleksandr Tymoshenko } 6232b3f6d66SOleksandr Tymoshenko 6242b3f6d66SOleksandr Tymoshenko static void 62598a7606bSVladimir Kondratyev evdev_mt_send_st_compat(struct evdev_dev *evdev) 6262b3f6d66SOleksandr Tymoshenko { 6272dc7188eSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 628fbe17f90SVladimir Kondratyev int nfingers, i, st_slot; 6292b3f6d66SOleksandr Tymoshenko 6302b3f6d66SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 6312b3f6d66SOleksandr Tymoshenko 6322dc7188eSVladimir Kondratyev nfingers = bitcount(mt->touches); 6332b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0); 6342b3f6d66SOleksandr Tymoshenko 635fbe17f90SVladimir Kondratyev /* Send first active MT-slot state as single touch report */ 636fbe17f90SVladimir Kondratyev st_slot = ffs(mt->touches) - 1; 637fbe17f90SVladimir Kondratyev if (st_slot != -1) 638127e54deSVladimir Kondratyev FOREACHBIT(mt->mtst_events, i) 639127e54deSVladimir Kondratyev evdev_send_event(evdev, EV_ABS, evdev_mtstmap[i].st, 640127e54deSVladimir Kondratyev evdev_mt_normalize(evdev_mt_get_value(evdev, 641127e54deSVladimir Kondratyev st_slot, evdev_mtstmap[i].mt), 642127e54deSVladimir Kondratyev evdev->ev_absinfo[evdev_mtstmap[i].mt].minimum, 643127e54deSVladimir Kondratyev evdev->ev_absinfo[evdev_mtstmap[i].mt].maximum, 644127e54deSVladimir Kondratyev evdev_mtstmap[i].max)); 6452b3f6d66SOleksandr Tymoshenko 6462b3f6d66SOleksandr Tymoshenko /* Touchscreens should not report tool taps */ 6472b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 6482b3f6d66SOleksandr Tymoshenko evdev_send_nfingers(evdev, nfingers); 6492b3f6d66SOleksandr Tymoshenko 6502b3f6d66SOleksandr Tymoshenko if (nfingers == 0) 6512b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0); 6522b3f6d66SOleksandr Tymoshenko } 6532b3f6d66SOleksandr Tymoshenko 65498a7606bSVladimir Kondratyev static void 65598a7606bSVladimir Kondratyev evdev_mt_send_autorel(struct evdev_dev *evdev) 656c736a757SOleksandr Tymoshenko { 65798a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 65898a7606bSVladimir Kondratyev int slot; 659c736a757SOleksandr Tymoshenko 660c736a757SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 661f76051c7SVladimir Kondratyev KASSERT(mt->match_frame == 0, ("Unmatched events exist")); 662c736a757SOleksandr Tymoshenko 66305936028SVladimir Kondratyev FOREACHBIT(mt->touches & ~mt->frame, slot) 66405936028SVladimir Kondratyev evdev_mt_send_slot(evdev, slot, NULL); 665c736a757SOleksandr Tymoshenko } 66698a7606bSVladimir Kondratyev 66798a7606bSVladimir Kondratyev void 66898a7606bSVladimir Kondratyev evdev_mt_push_autorel(struct evdev_dev *evdev) 66998a7606bSVladimir Kondratyev { 67098a7606bSVladimir Kondratyev EVDEV_ENTER(evdev); 67198a7606bSVladimir Kondratyev evdev_mt_send_autorel(evdev); 67298a7606bSVladimir Kondratyev EVDEV_EXIT(evdev); 67398a7606bSVladimir Kondratyev } 674