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]; 82*d056693dSVladimir 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 9698a7606bSVladimir Kondratyev static void evdev_mt_send_st_compat(struct evdev_dev *); 9798a7606bSVladimir Kondratyev static void evdev_mt_send_autorel(struct evdev_dev *); 98f76051c7SVladimir Kondratyev static void evdev_mt_replay_events(struct evdev_dev *); 9998a7606bSVladimir Kondratyev 1002dc7188eSVladimir Kondratyev static inline int 1012dc7188eSVladimir Kondratyev ffc_slot(struct evdev_dev *evdev, slotset_t slots) 1022dc7188eSVladimir Kondratyev { 1032dc7188eSVladimir Kondratyev return (ffs(~slots & (2U << MAXIMAL_MT_SLOT(evdev)) - 1) - 1); 1042dc7188eSVladimir Kondratyev } 1052dc7188eSVladimir Kondratyev 1062b3f6d66SOleksandr Tymoshenko void 1072b3f6d66SOleksandr Tymoshenko evdev_mt_init(struct evdev_dev *evdev) 1082b3f6d66SOleksandr Tymoshenko { 1094c0a134eSVladimir Kondratyev struct evdev_mt *mt; 1104c0a134eSVladimir Kondratyev size_t size = offsetof(struct evdev_mt, slots); 11198a7606bSVladimir Kondratyev int slot, slots; 112*d056693dSVladimir Kondratyev bool type_a; 113*d056693dSVladimir Kondratyev 114*d056693dSVladimir Kondratyev type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT); 115*d056693dSVladimir Kondratyev if (type_a) { 116*d056693dSVladimir Kondratyev /* Add events produced by MT type A to type B converter */ 117*d056693dSVladimir Kondratyev evdev_support_abs(evdev, 118*d056693dSVladimir Kondratyev ABS_MT_SLOT, 0, MAX_MT_SLOTS - 1, 0, 0, 0); 119*d056693dSVladimir Kondratyev evdev_support_abs(evdev, 120*d056693dSVladimir Kondratyev ABS_MT_TRACKING_ID, -1, MAX_MT_SLOTS - 1, 0, 0, 0); 121*d056693dSVladimir Kondratyev } 1222b3f6d66SOleksandr Tymoshenko 1232b3f6d66SOleksandr Tymoshenko slots = MAXIMAL_MT_SLOT(evdev) + 1; 1244c0a134eSVladimir Kondratyev size += sizeof(mt->slots[0]) * slots; 1254c0a134eSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) { 126f76051c7SVladimir Kondratyev size += sizeof(mt->match_slots[0]) * slots; 1274c0a134eSVladimir Kondratyev size += sizeof(mt->matrix[0]) * (slots + 6) * slots; 1284c0a134eSVladimir Kondratyev } 1292b3f6d66SOleksandr Tymoshenko 1304c0a134eSVladimir Kondratyev mt = malloc(size, M_EVDEV, M_WAITOK | M_ZERO); 1314c0a134eSVladimir Kondratyev evdev->ev_mt = mt; 132*d056693dSVladimir Kondratyev mt->type_a = type_a; 1334c0a134eSVladimir Kondratyev 1344c0a134eSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) { 135f76051c7SVladimir Kondratyev mt->match_slots = mt->slots + slots; 136f76051c7SVladimir Kondratyev mt->matrix = (int *)(mt->match_slots + slots); 1374c0a134eSVladimir Kondratyev } 1382b3f6d66SOleksandr Tymoshenko 1392b3f6d66SOleksandr Tymoshenko /* Initialize multitouch protocol type B states */ 1402dc7188eSVladimir Kondratyev for (slot = 0; slot < slots; slot++) 141f76051c7SVladimir Kondratyev mt->slots[slot].id = -1; 1422b3f6d66SOleksandr Tymoshenko 14366bd52f5SVladimir Kondratyev if (!bit_test(evdev->ev_flags, EVDEV_FLAG_MT_KEEPID)) 14466bd52f5SVladimir Kondratyev evdev_support_abs(evdev, 14566bd52f5SVladimir 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 1512b3f6d66SOleksandr Tymoshenko evdev_mt_free(struct evdev_dev *evdev) 1522b3f6d66SOleksandr Tymoshenko { 1532b3f6d66SOleksandr Tymoshenko free(evdev->ev_mt, M_EVDEV); 1542b3f6d66SOleksandr Tymoshenko } 1552b3f6d66SOleksandr Tymoshenko 15698a7606bSVladimir Kondratyev void 15798a7606bSVladimir Kondratyev evdev_mt_sync_frame(struct evdev_dev *evdev) 1582b3f6d66SOleksandr Tymoshenko { 159f76051c7SVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) 160f76051c7SVladimir Kondratyev evdev_mt_replay_events(evdev); 16198a7606bSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL)) 16298a7606bSVladimir Kondratyev evdev_mt_send_autorel(evdev); 16398a7606bSVladimir Kondratyev if (evdev->ev_report_opened && 16498a7606bSVladimir Kondratyev bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) 16598a7606bSVladimir Kondratyev evdev_mt_send_st_compat(evdev); 1662dc7188eSVladimir Kondratyev evdev->ev_mt->frame = 0; 16798a7606bSVladimir Kondratyev } 1682b3f6d66SOleksandr Tymoshenko 16905936028SVladimir Kondratyev static void 17005936028SVladimir Kondratyev evdev_mt_send_slot(struct evdev_dev *evdev, int slot, 17105936028SVladimir Kondratyev union evdev_mt_slot *state) 17205936028SVladimir Kondratyev { 17305936028SVladimir Kondratyev int i; 17405936028SVladimir Kondratyev bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT); 17505936028SVladimir Kondratyev 17605936028SVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev); 17705936028SVladimir Kondratyev MPASS(type_a || (slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev))); 17805936028SVladimir Kondratyev MPASS(!type_a || state != NULL); 17905936028SVladimir Kondratyev 18005936028SVladimir Kondratyev if (!type_a) { 18105936028SVladimir Kondratyev evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot); 18205936028SVladimir Kondratyev if (state == NULL) { 18305936028SVladimir Kondratyev evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID, -1); 18405936028SVladimir Kondratyev return; 18505936028SVladimir Kondratyev } 18605936028SVladimir Kondratyev } 18705936028SVladimir Kondratyev bit_foreach_at(evdev->ev_abs_flags, ABS_MT_FIRST, ABS_MT_LAST + 1, i) 18805936028SVladimir Kondratyev evdev_send_event(evdev, EV_ABS, i, 18905936028SVladimir Kondratyev state->val[ABS_MT_INDEX(i)]); 19005936028SVladimir Kondratyev if (type_a) 19105936028SVladimir Kondratyev evdev_send_event(evdev, EV_SYN, SYN_MT_REPORT, 1); 19205936028SVladimir Kondratyev } 19305936028SVladimir Kondratyev 19405936028SVladimir Kondratyev int 19505936028SVladimir Kondratyev evdev_mt_push_slot(struct evdev_dev *evdev, int slot, 19605936028SVladimir Kondratyev union evdev_mt_slot *state) 19705936028SVladimir Kondratyev { 198f76051c7SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 19905936028SVladimir Kondratyev bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT); 20005936028SVladimir Kondratyev 201*d056693dSVladimir Kondratyev if ((type_a || (mt != NULL && mt->type_a)) && state == NULL) 20205936028SVladimir Kondratyev return (EINVAL); 20305936028SVladimir Kondratyev if (!type_a && (slot < 0 || slot > MAXIMAL_MT_SLOT(evdev))) 20405936028SVladimir Kondratyev return (EINVAL); 20505936028SVladimir Kondratyev 20605936028SVladimir Kondratyev EVDEV_ENTER(evdev); 207*d056693dSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK) && mt->type_a) { 208*d056693dSVladimir Kondratyev mt->match_slots[mt->match_slot] = *state; 209*d056693dSVladimir Kondratyev evdev_mt_record_event(evdev, EV_SYN, SYN_MT_REPORT, 1); 210*d056693dSVladimir Kondratyev } else if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) { 211f76051c7SVladimir Kondratyev evdev_mt_record_event(evdev, EV_ABS, ABS_MT_SLOT, slot); 212f76051c7SVladimir Kondratyev if (state != NULL) 213f76051c7SVladimir Kondratyev mt->match_slots[mt->match_slot] = *state; 214f76051c7SVladimir Kondratyev else 215f76051c7SVladimir Kondratyev evdev_mt_record_event(evdev, EV_ABS, 216f76051c7SVladimir Kondratyev ABS_MT_TRACKING_ID, -1); 217f76051c7SVladimir Kondratyev } else 21805936028SVladimir Kondratyev evdev_mt_send_slot(evdev, slot, state); 21905936028SVladimir Kondratyev EVDEV_EXIT(evdev); 22005936028SVladimir Kondratyev 22105936028SVladimir Kondratyev return (0); 22205936028SVladimir Kondratyev } 22305936028SVladimir Kondratyev 2244c0a134eSVladimir Kondratyev /* 2254c0a134eSVladimir Kondratyev * Find a minimum-weight matching for an m-by-n matrix. 2264c0a134eSVladimir Kondratyev * 2274c0a134eSVladimir Kondratyev * m must be greater than or equal to n. The size of the buffer must be 2284c0a134eSVladimir Kondratyev * at least 3m + 3n. 2294c0a134eSVladimir Kondratyev * 2304c0a134eSVladimir Kondratyev * On return, the first m elements of the buffer contain the row-to- 2314c0a134eSVladimir Kondratyev * column mappings, i.e., buffer[i] is the column index for row i, or -1 2324c0a134eSVladimir Kondratyev * if there is no assignment for that row (which may happen if n < m). 2334c0a134eSVladimir Kondratyev * 2344c0a134eSVladimir Kondratyev * Wrong results because of overflows will not occur with input values 2354c0a134eSVladimir Kondratyev * in the range of 0 to INT_MAX / 2 inclusive. 2364c0a134eSVladimir Kondratyev * 2374c0a134eSVladimir Kondratyev * The function applies the Dinic-Kronrod algorithm. It is not modern or 2384c0a134eSVladimir Kondratyev * popular, but it seems to be a good choice for small matrices at least. 2394c0a134eSVladimir Kondratyev * The original form of the algorithm is modified as follows: There is no 2404c0a134eSVladimir Kondratyev * initial search for row minima, the initial assignments are in a 2414c0a134eSVladimir Kondratyev * "virtual" column with the index -1 and zero values. This permits inputs 2424c0a134eSVladimir Kondratyev * with n < m, and it simplifies the reassignments. 2434c0a134eSVladimir Kondratyev */ 2444c0a134eSVladimir Kondratyev static void 2454c0a134eSVladimir Kondratyev evdev_mt_matching(int *matrix, int m, int n, int *buffer) 2464c0a134eSVladimir Kondratyev { 2474c0a134eSVladimir Kondratyev int i, j, k, d, e, row, col, delta; 2484c0a134eSVladimir Kondratyev int *p; 2494c0a134eSVladimir Kondratyev int *r2c = buffer; /* row-to-column assignments */ 2504c0a134eSVladimir Kondratyev int *red = r2c + m; /* reduced values of the assignments */ 2514c0a134eSVladimir Kondratyev int *mc = red + m; /* row-wise minimal elements of cs */ 2524c0a134eSVladimir Kondratyev int *cs = mc + m; /* the column set */ 2534c0a134eSVladimir Kondratyev int *c2r = cs + n; /* column-to-row assignments in cs */ 2544c0a134eSVladimir Kondratyev int *cd = c2r + n; /* column deltas (reduction) */ 2554c0a134eSVladimir Kondratyev 2564c0a134eSVladimir Kondratyev for (p = r2c; p < red; *p++ = -1) {} 2574c0a134eSVladimir Kondratyev for (; p < mc; *p++ = 0) {} 2584c0a134eSVladimir Kondratyev for (col = 0; col < n; col++) { 2594c0a134eSVladimir Kondratyev delta = INT_MAX; 2604c0a134eSVladimir Kondratyev for (i = 0, p = matrix + col; i < m; i++, p += n) { 2614c0a134eSVladimir Kondratyev d = *p - red[i]; 2624c0a134eSVladimir Kondratyev if (d < delta || (d == delta && r2c[i] < 0)) { 2634c0a134eSVladimir Kondratyev delta = d; 2644c0a134eSVladimir Kondratyev row = i; 2654c0a134eSVladimir Kondratyev } 2664c0a134eSVladimir Kondratyev } 2674c0a134eSVladimir Kondratyev cd[col] = delta; 2684c0a134eSVladimir Kondratyev if (r2c[row] < 0) { 2694c0a134eSVladimir Kondratyev r2c[row] = col; 2704c0a134eSVladimir Kondratyev continue; 2714c0a134eSVladimir Kondratyev } 2724c0a134eSVladimir Kondratyev for (p = mc; p < cs; *p++ = col) {} 2734c0a134eSVladimir Kondratyev for (k = 0; (j = r2c[row]) >= 0;) { 2744c0a134eSVladimir Kondratyev cs[k++] = j; 2754c0a134eSVladimir Kondratyev c2r[j] = row; 2764c0a134eSVladimir Kondratyev mc[row] -= n; 2774c0a134eSVladimir Kondratyev delta = INT_MAX; 2784c0a134eSVladimir Kondratyev for (i = 0, p = matrix; i < m; i++, p += n) 2794c0a134eSVladimir Kondratyev if (mc[i] >= 0) { 2804c0a134eSVladimir Kondratyev d = p[mc[i]] - cd[mc[i]]; 2814c0a134eSVladimir Kondratyev e = p[j] - cd[j]; 2824c0a134eSVladimir Kondratyev if (e < d) { 2834c0a134eSVladimir Kondratyev d = e; 2844c0a134eSVladimir Kondratyev mc[i] = j; 2854c0a134eSVladimir Kondratyev } 2864c0a134eSVladimir Kondratyev d -= red[i]; 2874c0a134eSVladimir Kondratyev if (d < delta || (d == delta 2884c0a134eSVladimir Kondratyev && r2c[i] < 0)) { 2894c0a134eSVladimir Kondratyev delta = d; 2904c0a134eSVladimir Kondratyev row = i; 2914c0a134eSVladimir Kondratyev } 2924c0a134eSVladimir Kondratyev } 2934c0a134eSVladimir Kondratyev cd[col] += delta; 2944c0a134eSVladimir Kondratyev for (i = 0; i < k; i++) { 2954c0a134eSVladimir Kondratyev cd[cs[i]] += delta; 2964c0a134eSVladimir Kondratyev red[c2r[cs[i]]] -= delta; 2974c0a134eSVladimir Kondratyev } 2984c0a134eSVladimir Kondratyev } 2994c0a134eSVladimir Kondratyev for (j = mc[row]; (r2c[row] = j) != col;) { 3004c0a134eSVladimir Kondratyev row = c2r[j]; 3014c0a134eSVladimir Kondratyev j = mc[row] + n; 3024c0a134eSVladimir Kondratyev } 3034c0a134eSVladimir Kondratyev } 3044c0a134eSVladimir Kondratyev } 3054c0a134eSVladimir Kondratyev 3064c0a134eSVladimir Kondratyev /* 3074c0a134eSVladimir Kondratyev * Assign tracking IDs to the points in the pt array. The tracking ID 3084c0a134eSVladimir Kondratyev * assignment pairs the points with points of the previous frame in 3094c0a134eSVladimir Kondratyev * such a way that the sum of the squared distances is minimal. Using 3104c0a134eSVladimir Kondratyev * squares instead of simple distances favours assignments with more uniform 3114c0a134eSVladimir Kondratyev * distances, and it is faster. 3124c0a134eSVladimir Kondratyev * Set tracking id to -1 for unassigned (new) points. 3134c0a134eSVladimir Kondratyev */ 3144c0a134eSVladimir Kondratyev void 3154c0a134eSVladimir Kondratyev evdev_mt_match_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, 3164c0a134eSVladimir Kondratyev int size) 3174c0a134eSVladimir Kondratyev { 3184c0a134eSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 3194c0a134eSVladimir Kondratyev int i, j, m, n, dx, dy, slot, num_touches; 3204c0a134eSVladimir Kondratyev int *p, *r2c, *c2r; 3214c0a134eSVladimir Kondratyev 3224c0a134eSVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev); 3234c0a134eSVladimir Kondratyev MPASS(mt->matrix != NULL); 3244c0a134eSVladimir Kondratyev MPASS(size >= 0 && size <= MAXIMAL_MT_SLOT(evdev) + 1); 3254c0a134eSVladimir Kondratyev 3264c0a134eSVladimir Kondratyev if (size == 0) 3274c0a134eSVladimir Kondratyev return; 3284c0a134eSVladimir Kondratyev 3294c0a134eSVladimir Kondratyev p = mt->matrix; 3304c0a134eSVladimir Kondratyev num_touches = bitcount(mt->touches); 3314c0a134eSVladimir Kondratyev if (num_touches >= size) { 3324c0a134eSVladimir Kondratyev FOREACHBIT(mt->touches, slot) 3334c0a134eSVladimir Kondratyev for (i = 0; i < size; i++) { 3344c0a134eSVladimir Kondratyev dx = pt[i].x - mt->slots[slot].x; 3354c0a134eSVladimir Kondratyev dy = pt[i].y - mt->slots[slot].y; 3364c0a134eSVladimir Kondratyev *p++ = dx * dx + dy * dy; 3374c0a134eSVladimir Kondratyev } 3384c0a134eSVladimir Kondratyev m = num_touches; 3394c0a134eSVladimir Kondratyev n = size; 3404c0a134eSVladimir Kondratyev } else { 3414c0a134eSVladimir Kondratyev for (i = 0; i < size; i++) 3424c0a134eSVladimir Kondratyev FOREACHBIT(mt->touches, slot) { 3434c0a134eSVladimir Kondratyev dx = pt[i].x - mt->slots[slot].x; 3444c0a134eSVladimir Kondratyev dy = pt[i].y - mt->slots[slot].y; 3454c0a134eSVladimir Kondratyev *p++ = dx * dx + dy * dy; 3464c0a134eSVladimir Kondratyev } 3474c0a134eSVladimir Kondratyev m = size; 3484c0a134eSVladimir Kondratyev n = num_touches; 3494c0a134eSVladimir Kondratyev } 3504c0a134eSVladimir Kondratyev evdev_mt_matching(mt->matrix, m, n, p); 3514c0a134eSVladimir Kondratyev 3524c0a134eSVladimir Kondratyev r2c = p; 3534c0a134eSVladimir Kondratyev c2r = p + m; 3544c0a134eSVladimir Kondratyev for (i = 0; i < m; i++) 3554c0a134eSVladimir Kondratyev if ((j = r2c[i]) >= 0) 3564c0a134eSVladimir Kondratyev c2r[j] = i; 3574c0a134eSVladimir Kondratyev 3584c0a134eSVladimir Kondratyev p = (n == size ? c2r : r2c); 3594c0a134eSVladimir Kondratyev for (i = 0; i < size; i++) 3604c0a134eSVladimir Kondratyev if (*p++ < 0) 3614c0a134eSVladimir Kondratyev pt[i].id = -1; 3624c0a134eSVladimir Kondratyev 3634c0a134eSVladimir Kondratyev p = (n == size ? r2c : c2r); 3644c0a134eSVladimir Kondratyev FOREACHBIT(mt->touches, slot) 3654c0a134eSVladimir Kondratyev if ((i = *p++) >= 0) 3664c0a134eSVladimir Kondratyev pt[i].id = mt->tracking_ids[slot]; 3674c0a134eSVladimir Kondratyev } 3684c0a134eSVladimir Kondratyev 3694c0a134eSVladimir Kondratyev static void 3704c0a134eSVladimir Kondratyev evdev_mt_send_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, int size) 3714c0a134eSVladimir Kondratyev { 3724c0a134eSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 3734c0a134eSVladimir Kondratyev union evdev_mt_slot *slot; 3744c0a134eSVladimir Kondratyev 3754c0a134eSVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev); 3764c0a134eSVladimir Kondratyev MPASS(size >= 0 && size <= MAXIMAL_MT_SLOT(evdev) + 1); 3774c0a134eSVladimir Kondratyev 3784c0a134eSVladimir Kondratyev /* 3794c0a134eSVladimir Kondratyev * While MT-matching assign tracking IDs of new contacts to be equal 3804c0a134eSVladimir Kondratyev * to a slot number to make things simpler. 3814c0a134eSVladimir Kondratyev */ 3824c0a134eSVladimir Kondratyev for (slot = pt; slot < pt + size; slot++) { 3834c0a134eSVladimir Kondratyev if (slot->id < 0) 3844c0a134eSVladimir Kondratyev slot->id = ffc_slot(evdev, mt->touches | mt->frame); 3854c0a134eSVladimir Kondratyev if (slot->id >= 0) 3864c0a134eSVladimir Kondratyev evdev_mt_send_slot(evdev, slot->id, slot); 3874c0a134eSVladimir Kondratyev } 3884c0a134eSVladimir Kondratyev } 3894c0a134eSVladimir Kondratyev 3904c0a134eSVladimir Kondratyev int 3914c0a134eSVladimir Kondratyev evdev_mt_push_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, int size) 3924c0a134eSVladimir Kondratyev { 3934c0a134eSVladimir Kondratyev if (size < 0 || size > MAXIMAL_MT_SLOT(evdev) + 1) 3944c0a134eSVladimir Kondratyev return (EINVAL); 3954c0a134eSVladimir Kondratyev 3964c0a134eSVladimir Kondratyev EVDEV_ENTER(evdev); 3974c0a134eSVladimir Kondratyev evdev_mt_send_frame(evdev, pt, size); 3984c0a134eSVladimir Kondratyev EVDEV_EXIT(evdev); 3994c0a134eSVladimir Kondratyev 4004c0a134eSVladimir Kondratyev return (0); 4014c0a134eSVladimir Kondratyev } 4024c0a134eSVladimir Kondratyev 403f76051c7SVladimir Kondratyev bool 404f76051c7SVladimir Kondratyev evdev_mt_record_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, 405f76051c7SVladimir Kondratyev int32_t value) 406f76051c7SVladimir Kondratyev { 407f76051c7SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 408f76051c7SVladimir Kondratyev 409f76051c7SVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev); 410f76051c7SVladimir Kondratyev 411f76051c7SVladimir Kondratyev switch (type) { 412*d056693dSVladimir Kondratyev case EV_SYN: 413*d056693dSVladimir Kondratyev if (code == SYN_MT_REPORT) { 414*d056693dSVladimir Kondratyev /* MT protocol type A support */ 415*d056693dSVladimir Kondratyev KASSERT(mt->type_a, ("Not a MT type A protocol")); 416*d056693dSVladimir Kondratyev mt->match_frame |= 1U << mt->match_slot; 417*d056693dSVladimir Kondratyev mt->match_slot++; 418*d056693dSVladimir Kondratyev return (true); 419*d056693dSVladimir Kondratyev } 420*d056693dSVladimir Kondratyev break; 421f76051c7SVladimir Kondratyev case EV_ABS: 422f76051c7SVladimir Kondratyev if (code == ABS_MT_SLOT) { 423f76051c7SVladimir Kondratyev /* MT protocol type B support */ 424*d056693dSVladimir Kondratyev KASSERT(!mt->type_a, ("Not a MT type B protocol")); 425f76051c7SVladimir Kondratyev KASSERT(value >= 0, ("Negative slot number")); 426f76051c7SVladimir Kondratyev mt->match_slot = value; 427f76051c7SVladimir Kondratyev mt->match_frame |= 1U << mt->match_slot; 428f76051c7SVladimir Kondratyev return (true); 429f76051c7SVladimir Kondratyev } else if (code == ABS_MT_TRACKING_ID) { 430*d056693dSVladimir Kondratyev KASSERT(!mt->type_a, ("Not a MT type B protocol")); 431f76051c7SVladimir Kondratyev if (value == -1) 432f76051c7SVladimir Kondratyev mt->match_frame &= ~(1U << mt->match_slot); 433f76051c7SVladimir Kondratyev return (true); 434f76051c7SVladimir Kondratyev } else if (ABS_IS_MT(code)) { 435f76051c7SVladimir Kondratyev KASSERT(mt->match_slot >= 0, ("Negative slot")); 436f76051c7SVladimir Kondratyev KASSERT(mt->match_slot <= MAXIMAL_MT_SLOT(evdev), 437f76051c7SVladimir Kondratyev ("Slot number too big")); 438f76051c7SVladimir Kondratyev mt->match_slots[mt->match_slot]. 439f76051c7SVladimir Kondratyev val[ABS_MT_INDEX(code)] = value; 440f76051c7SVladimir Kondratyev return (true); 441f76051c7SVladimir Kondratyev } 442f76051c7SVladimir Kondratyev break; 443f76051c7SVladimir Kondratyev default: 444f76051c7SVladimir Kondratyev break; 445f76051c7SVladimir Kondratyev } 446f76051c7SVladimir Kondratyev 447f76051c7SVladimir Kondratyev return (false); 448f76051c7SVladimir Kondratyev } 449f76051c7SVladimir Kondratyev 450f76051c7SVladimir Kondratyev static void 451f76051c7SVladimir Kondratyev evdev_mt_replay_events(struct evdev_dev *evdev) 452f76051c7SVladimir Kondratyev { 453f76051c7SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 454f76051c7SVladimir Kondratyev int slot, size = 0; 455f76051c7SVladimir Kondratyev 456f76051c7SVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev); 457f76051c7SVladimir Kondratyev 458f76051c7SVladimir Kondratyev FOREACHBIT(mt->match_frame, slot) { 459f76051c7SVladimir Kondratyev if (slot != size) 460f76051c7SVladimir Kondratyev mt->match_slots[size] = mt->match_slots[slot]; 461f76051c7SVladimir Kondratyev size++; 462f76051c7SVladimir Kondratyev } 463f76051c7SVladimir Kondratyev evdev_mt_match_frame(evdev, mt->match_slots, size); 464f76051c7SVladimir Kondratyev evdev_mt_send_frame(evdev, mt->match_slots, size); 465f76051c7SVladimir Kondratyev mt->match_slot = 0; 466f76051c7SVladimir Kondratyev mt->match_frame = 0; 467f76051c7SVladimir Kondratyev } 468f76051c7SVladimir Kondratyev 469f76051c7SVladimir Kondratyev union evdev_mt_slot * 470f76051c7SVladimir Kondratyev evdev_mt_get_match_slots(struct evdev_dev *evdev) 471f76051c7SVladimir Kondratyev { 472f76051c7SVladimir Kondratyev return (evdev->ev_mt->match_slots); 473f76051c7SVladimir Kondratyev } 474f76051c7SVladimir Kondratyev 47598a7606bSVladimir Kondratyev int 47698a7606bSVladimir Kondratyev evdev_mt_get_last_slot(struct evdev_dev *evdev) 47798a7606bSVladimir Kondratyev { 47898a7606bSVladimir Kondratyev return (evdev->ev_mt->last_reported_slot); 4792b3f6d66SOleksandr Tymoshenko } 4802b3f6d66SOleksandr Tymoshenko 4812b3f6d66SOleksandr Tymoshenko void 48298a7606bSVladimir Kondratyev evdev_mt_set_last_slot(struct evdev_dev *evdev, int slot) 4832b3f6d66SOleksandr Tymoshenko { 48498a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 4852b3f6d66SOleksandr Tymoshenko 48698a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 4872b3f6d66SOleksandr Tymoshenko 4882dc7188eSVladimir Kondratyev mt->frame |= 1U << slot; 48998a7606bSVladimir Kondratyev mt->last_reported_slot = slot; 4902b3f6d66SOleksandr Tymoshenko } 4912b3f6d66SOleksandr Tymoshenko 4922b3f6d66SOleksandr Tymoshenko int32_t 49398a7606bSVladimir Kondratyev evdev_mt_get_value(struct evdev_dev *evdev, int slot, int16_t code) 49498a7606bSVladimir Kondratyev { 49598a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 49698a7606bSVladimir Kondratyev 49798a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 49898a7606bSVladimir Kondratyev 49998a7606bSVladimir Kondratyev return (mt->slots[slot].val[ABS_MT_INDEX(code)]); 50098a7606bSVladimir Kondratyev } 50198a7606bSVladimir Kondratyev 50298a7606bSVladimir Kondratyev void 50398a7606bSVladimir Kondratyev evdev_mt_set_value(struct evdev_dev *evdev, int slot, int16_t code, 50498a7606bSVladimir Kondratyev int32_t value) 50598a7606bSVladimir Kondratyev { 50698a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 50798a7606bSVladimir Kondratyev 50898a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 50998a7606bSVladimir Kondratyev 5102dc7188eSVladimir Kondratyev if (code == ABS_MT_TRACKING_ID) { 5112dc7188eSVladimir Kondratyev if (value != -1) 5122dc7188eSVladimir Kondratyev mt->touches |= 1U << slot; 5132dc7188eSVladimir Kondratyev else 5142dc7188eSVladimir Kondratyev mt->touches &= ~(1U << slot); 5152dc7188eSVladimir Kondratyev } 51698a7606bSVladimir Kondratyev mt->slots[slot].val[ABS_MT_INDEX(code)] = value; 51798a7606bSVladimir Kondratyev } 51898a7606bSVladimir Kondratyev 51998a7606bSVladimir Kondratyev int 5202b3f6d66SOleksandr Tymoshenko evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id) 5212b3f6d66SOleksandr Tymoshenko { 52298a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 5232dc7188eSVladimir Kondratyev int slot; 5242b3f6d66SOleksandr Tymoshenko 525*d056693dSVladimir Kondratyev KASSERT(!mt->type_a, ("Not a MT type B protocol")); 526*d056693dSVladimir Kondratyev 527f76051c7SVladimir Kondratyev /* 528f76051c7SVladimir Kondratyev * Ignore tracking_id if slot assignment is performed by evdev. 529f76051c7SVladimir Kondratyev * Events are written sequentially to temporary matching buffer. 530f76051c7SVladimir Kondratyev */ 531f76051c7SVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) 532f76051c7SVladimir Kondratyev return (ffc_slot(evdev, mt->match_frame)); 533f76051c7SVladimir Kondratyev 5342dc7188eSVladimir Kondratyev FOREACHBIT(mt->touches, slot) 53566bd52f5SVladimir Kondratyev if (mt->tracking_ids[slot] == tracking_id) 5362b3f6d66SOleksandr Tymoshenko return (slot); 5372b3f6d66SOleksandr Tymoshenko /* 5382dc7188eSVladimir Kondratyev * Do not allow allocation of new slot in a place of just 5392dc7188eSVladimir Kondratyev * released one within the same report. 5402b3f6d66SOleksandr Tymoshenko */ 5412dc7188eSVladimir Kondratyev return (ffc_slot(evdev, mt->touches | mt->frame)); 5422b3f6d66SOleksandr Tymoshenko } 5432b3f6d66SOleksandr Tymoshenko 54466bd52f5SVladimir Kondratyev int32_t 54566bd52f5SVladimir Kondratyev evdev_mt_reassign_id(struct evdev_dev *evdev, int slot, int32_t id) 54666bd52f5SVladimir Kondratyev { 54766bd52f5SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 54866bd52f5SVladimir Kondratyev int32_t nid; 54966bd52f5SVladimir Kondratyev 55066bd52f5SVladimir Kondratyev if (id == -1 || bit_test(evdev->ev_flags, EVDEV_FLAG_MT_KEEPID)) { 55166bd52f5SVladimir Kondratyev mt->tracking_ids[slot] = id; 55266bd52f5SVladimir Kondratyev return (id); 55366bd52f5SVladimir Kondratyev } 55466bd52f5SVladimir Kondratyev 55566bd52f5SVladimir Kondratyev nid = evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID); 55666bd52f5SVladimir Kondratyev if (nid != -1) { 55766bd52f5SVladimir Kondratyev KASSERT(id == mt->tracking_ids[slot], 55866bd52f5SVladimir Kondratyev ("MT-slot tracking id has changed")); 55966bd52f5SVladimir Kondratyev return (nid); 56066bd52f5SVladimir Kondratyev } 56166bd52f5SVladimir Kondratyev 56266bd52f5SVladimir Kondratyev mt->tracking_ids[slot] = id; 56366bd52f5SVladimir Kondratyev again: 56466bd52f5SVladimir Kondratyev nid = mt->tracking_id++; 56566bd52f5SVladimir Kondratyev FOREACHBIT(mt->touches, slot) 56666bd52f5SVladimir Kondratyev if (evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID) == nid) 56766bd52f5SVladimir Kondratyev goto again; 56866bd52f5SVladimir Kondratyev 56966bd52f5SVladimir Kondratyev return (nid); 57066bd52f5SVladimir Kondratyev } 57166bd52f5SVladimir Kondratyev 572127e54deSVladimir Kondratyev static inline int32_t 573127e54deSVladimir Kondratyev evdev_mt_normalize(int32_t value, int32_t mtmin, int32_t mtmax, int32_t stmax) 574127e54deSVladimir Kondratyev { 575127e54deSVladimir Kondratyev if (stmax != 0 && mtmax != mtmin) { 576127e54deSVladimir Kondratyev value = (value - mtmin) * stmax / (mtmax - mtmin); 577127e54deSVladimir Kondratyev value = MAX(MIN(value, stmax), 0); 578127e54deSVladimir Kondratyev } 579127e54deSVladimir Kondratyev return (value); 580127e54deSVladimir Kondratyev } 581127e54deSVladimir Kondratyev 5822b3f6d66SOleksandr Tymoshenko void 5832b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(struct evdev_dev *evdev) 5842b3f6d66SOleksandr Tymoshenko { 585127e54deSVladimir Kondratyev struct input_absinfo *ai; 58698a7606bSVladimir 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 */ 599127e54deSVladimir Kondratyev for (i = 0; i < nitems(evdev_mtstmap); i++) { 600127e54deSVladimir Kondratyev if (!bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].mt) || 601127e54deSVladimir Kondratyev bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].st)) 602127e54deSVladimir Kondratyev continue; 603127e54deSVladimir Kondratyev ai = evdev->ev_absinfo + evdev_mtstmap[i].mt; 604127e54deSVladimir Kondratyev evdev->ev_mt->mtst_events |= 1U << i; 605127e54deSVladimir Kondratyev if (evdev_mtstmap[i].max != 0) 606127e54deSVladimir Kondratyev evdev_support_abs(evdev, evdev_mtstmap[i].st, 607314913edSVladimir Kondratyev 0, 608127e54deSVladimir Kondratyev evdev_mtstmap[i].max, 609127e54deSVladimir Kondratyev 0, 610127e54deSVladimir Kondratyev evdev_mt_normalize( 611127e54deSVladimir Kondratyev ai->flat, 0, ai->maximum, evdev_mtstmap[i].max), 612127e54deSVladimir Kondratyev 0); 613127e54deSVladimir Kondratyev else 614127e54deSVladimir Kondratyev evdev_support_abs(evdev, evdev_mtstmap[i].st, 615127e54deSVladimir Kondratyev ai->minimum, 616127e54deSVladimir Kondratyev ai->maximum, 617127e54deSVladimir Kondratyev 0, 618127e54deSVladimir Kondratyev ai->flat, 619127e54deSVladimir Kondratyev ai->resolution); 620127e54deSVladimir Kondratyev } 6212b3f6d66SOleksandr Tymoshenko } 6222b3f6d66SOleksandr Tymoshenko 6232b3f6d66SOleksandr Tymoshenko static void 62498a7606bSVladimir Kondratyev evdev_mt_send_st_compat(struct evdev_dev *evdev) 6252b3f6d66SOleksandr Tymoshenko { 6262dc7188eSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 627fbe17f90SVladimir Kondratyev int nfingers, i, st_slot; 6282b3f6d66SOleksandr Tymoshenko 6292b3f6d66SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 6302b3f6d66SOleksandr Tymoshenko 6312dc7188eSVladimir Kondratyev nfingers = bitcount(mt->touches); 6322b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0); 6332b3f6d66SOleksandr Tymoshenko 634fbe17f90SVladimir Kondratyev /* Send first active MT-slot state as single touch report */ 635fbe17f90SVladimir Kondratyev st_slot = ffs(mt->touches) - 1; 636fbe17f90SVladimir Kondratyev if (st_slot != -1) 637127e54deSVladimir Kondratyev FOREACHBIT(mt->mtst_events, i) 638127e54deSVladimir Kondratyev evdev_send_event(evdev, EV_ABS, evdev_mtstmap[i].st, 639127e54deSVladimir Kondratyev evdev_mt_normalize(evdev_mt_get_value(evdev, 640127e54deSVladimir Kondratyev st_slot, evdev_mtstmap[i].mt), 641127e54deSVladimir Kondratyev evdev->ev_absinfo[evdev_mtstmap[i].mt].minimum, 642127e54deSVladimir Kondratyev evdev->ev_absinfo[evdev_mtstmap[i].mt].maximum, 643127e54deSVladimir 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 6542b3f6d66SOleksandr Tymoshenko evdev_push_mt_compat(struct evdev_dev *evdev) 6552b3f6d66SOleksandr Tymoshenko { 6562b3f6d66SOleksandr Tymoshenko 6574c0a4665SVladimir Kondratyev EVDEV_ENTER(evdev); 65898a7606bSVladimir Kondratyev evdev_mt_send_st_compat(evdev); 6594c0a4665SVladimir Kondratyev EVDEV_EXIT(evdev); 6602b3f6d66SOleksandr Tymoshenko } 661c736a757SOleksandr Tymoshenko 66298a7606bSVladimir Kondratyev static void 66398a7606bSVladimir Kondratyev evdev_mt_send_autorel(struct evdev_dev *evdev) 664c736a757SOleksandr Tymoshenko { 66598a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 66698a7606bSVladimir Kondratyev int slot; 667c736a757SOleksandr Tymoshenko 668c736a757SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 669f76051c7SVladimir Kondratyev KASSERT(mt->match_frame == 0, ("Unmatched events exist")); 670c736a757SOleksandr Tymoshenko 67105936028SVladimir Kondratyev FOREACHBIT(mt->touches & ~mt->frame, slot) 67205936028SVladimir Kondratyev evdev_mt_send_slot(evdev, slot, NULL); 673c736a757SOleksandr Tymoshenko } 67498a7606bSVladimir Kondratyev 67598a7606bSVladimir Kondratyev void 67698a7606bSVladimir Kondratyev evdev_mt_push_autorel(struct evdev_dev *evdev) 67798a7606bSVladimir Kondratyev { 67898a7606bSVladimir Kondratyev EVDEV_ENTER(evdev); 67998a7606bSVladimir Kondratyev evdev_mt_send_autorel(evdev); 68098a7606bSVladimir Kondratyev EVDEV_EXIT(evdev); 68198a7606bSVladimir Kondratyev } 682