12b3f6d66SOleksandr Tymoshenko /*- 2*f76051c7SVladimir 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]; 82127e54deSVladimir Kondratyev u_int mtst_events; 832dc7188eSVladimir Kondratyev /* the set of slots with active touches */ 842dc7188eSVladimir Kondratyev slotset_t touches; 852dc7188eSVladimir Kondratyev /* the set of slots with unsynchronized state */ 862dc7188eSVladimir Kondratyev slotset_t frame; 87*f76051c7SVladimir Kondratyev /* the set of slots to match with active touches */ 88*f76051c7SVladimir Kondratyev slotset_t match_frame; 89*f76051c7SVladimir Kondratyev int match_slot; 90*f76051c7SVladimir Kondratyev union evdev_mt_slot *match_slots; 914c0a134eSVladimir Kondratyev int *matrix; 9205936028SVladimir Kondratyev union evdev_mt_slot slots[]; 932b3f6d66SOleksandr Tymoshenko }; 942b3f6d66SOleksandr Tymoshenko 9598a7606bSVladimir Kondratyev static void evdev_mt_send_st_compat(struct evdev_dev *); 9698a7606bSVladimir Kondratyev static void evdev_mt_send_autorel(struct evdev_dev *); 97*f76051c7SVladimir Kondratyev static void evdev_mt_replay_events(struct evdev_dev *); 9898a7606bSVladimir Kondratyev 992dc7188eSVladimir Kondratyev static inline int 1002dc7188eSVladimir Kondratyev ffc_slot(struct evdev_dev *evdev, slotset_t slots) 1012dc7188eSVladimir Kondratyev { 1022dc7188eSVladimir Kondratyev return (ffs(~slots & (2U << MAXIMAL_MT_SLOT(evdev)) - 1) - 1); 1032dc7188eSVladimir Kondratyev } 1042dc7188eSVladimir Kondratyev 1052b3f6d66SOleksandr Tymoshenko void 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; 1112b3f6d66SOleksandr Tymoshenko 1122b3f6d66SOleksandr Tymoshenko slots = MAXIMAL_MT_SLOT(evdev) + 1; 1134c0a134eSVladimir Kondratyev size += sizeof(mt->slots[0]) * slots; 1144c0a134eSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) { 115*f76051c7SVladimir Kondratyev size += sizeof(mt->match_slots[0]) * slots; 1164c0a134eSVladimir Kondratyev size += sizeof(mt->matrix[0]) * (slots + 6) * slots; 1174c0a134eSVladimir Kondratyev } 1182b3f6d66SOleksandr Tymoshenko 1194c0a134eSVladimir Kondratyev mt = malloc(size, M_EVDEV, M_WAITOK | M_ZERO); 1204c0a134eSVladimir Kondratyev evdev->ev_mt = mt; 1214c0a134eSVladimir Kondratyev 1224c0a134eSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) { 123*f76051c7SVladimir Kondratyev mt->match_slots = mt->slots + slots; 124*f76051c7SVladimir Kondratyev mt->matrix = (int *)(mt->match_slots + slots); 1254c0a134eSVladimir Kondratyev } 1262b3f6d66SOleksandr Tymoshenko 1272b3f6d66SOleksandr Tymoshenko /* Initialize multitouch protocol type B states */ 1282dc7188eSVladimir Kondratyev for (slot = 0; slot < slots; slot++) 129*f76051c7SVladimir Kondratyev mt->slots[slot].id = -1; 1302b3f6d66SOleksandr Tymoshenko 13166bd52f5SVladimir Kondratyev if (!bit_test(evdev->ev_flags, EVDEV_FLAG_MT_KEEPID)) 13266bd52f5SVladimir Kondratyev evdev_support_abs(evdev, 13366bd52f5SVladimir Kondratyev ABS_MT_TRACKING_ID, -1, UINT16_MAX, 0, 0, 0); 1342b3f6d66SOleksandr Tymoshenko if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) 1352b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(evdev); 1362b3f6d66SOleksandr Tymoshenko } 1372b3f6d66SOleksandr Tymoshenko 1382b3f6d66SOleksandr Tymoshenko void 1392b3f6d66SOleksandr Tymoshenko evdev_mt_free(struct evdev_dev *evdev) 1402b3f6d66SOleksandr Tymoshenko { 1412b3f6d66SOleksandr Tymoshenko free(evdev->ev_mt, M_EVDEV); 1422b3f6d66SOleksandr Tymoshenko } 1432b3f6d66SOleksandr Tymoshenko 14498a7606bSVladimir Kondratyev void 14598a7606bSVladimir Kondratyev evdev_mt_sync_frame(struct evdev_dev *evdev) 1462b3f6d66SOleksandr Tymoshenko { 147*f76051c7SVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) 148*f76051c7SVladimir Kondratyev evdev_mt_replay_events(evdev); 14998a7606bSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL)) 15098a7606bSVladimir Kondratyev evdev_mt_send_autorel(evdev); 15198a7606bSVladimir Kondratyev if (evdev->ev_report_opened && 15298a7606bSVladimir Kondratyev bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) 15398a7606bSVladimir Kondratyev evdev_mt_send_st_compat(evdev); 1542dc7188eSVladimir Kondratyev evdev->ev_mt->frame = 0; 15598a7606bSVladimir Kondratyev } 1562b3f6d66SOleksandr Tymoshenko 15705936028SVladimir Kondratyev static void 15805936028SVladimir Kondratyev evdev_mt_send_slot(struct evdev_dev *evdev, int slot, 15905936028SVladimir Kondratyev union evdev_mt_slot *state) 16005936028SVladimir Kondratyev { 16105936028SVladimir Kondratyev int i; 16205936028SVladimir Kondratyev bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT); 16305936028SVladimir Kondratyev 16405936028SVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev); 16505936028SVladimir Kondratyev MPASS(type_a || (slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev))); 16605936028SVladimir Kondratyev MPASS(!type_a || state != NULL); 16705936028SVladimir Kondratyev 16805936028SVladimir Kondratyev if (!type_a) { 16905936028SVladimir Kondratyev evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot); 17005936028SVladimir Kondratyev if (state == NULL) { 17105936028SVladimir Kondratyev evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID, -1); 17205936028SVladimir Kondratyev return; 17305936028SVladimir Kondratyev } 17405936028SVladimir Kondratyev } 17505936028SVladimir Kondratyev bit_foreach_at(evdev->ev_abs_flags, ABS_MT_FIRST, ABS_MT_LAST + 1, i) 17605936028SVladimir Kondratyev evdev_send_event(evdev, EV_ABS, i, 17705936028SVladimir Kondratyev state->val[ABS_MT_INDEX(i)]); 17805936028SVladimir Kondratyev if (type_a) 17905936028SVladimir Kondratyev evdev_send_event(evdev, EV_SYN, SYN_MT_REPORT, 1); 18005936028SVladimir Kondratyev } 18105936028SVladimir Kondratyev 18205936028SVladimir Kondratyev int 18305936028SVladimir Kondratyev evdev_mt_push_slot(struct evdev_dev *evdev, int slot, 18405936028SVladimir Kondratyev union evdev_mt_slot *state) 18505936028SVladimir Kondratyev { 186*f76051c7SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 18705936028SVladimir Kondratyev bool type_a = !bit_test(evdev->ev_abs_flags, ABS_MT_SLOT); 18805936028SVladimir Kondratyev 18905936028SVladimir Kondratyev if (type_a && state == NULL) 19005936028SVladimir Kondratyev return (EINVAL); 19105936028SVladimir Kondratyev if (!type_a && (slot < 0 || slot > MAXIMAL_MT_SLOT(evdev))) 19205936028SVladimir Kondratyev return (EINVAL); 19305936028SVladimir Kondratyev 19405936028SVladimir Kondratyev EVDEV_ENTER(evdev); 195*f76051c7SVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) { 196*f76051c7SVladimir Kondratyev evdev_mt_record_event(evdev, EV_ABS, ABS_MT_SLOT, slot); 197*f76051c7SVladimir Kondratyev if (state != NULL) 198*f76051c7SVladimir Kondratyev mt->match_slots[mt->match_slot] = *state; 199*f76051c7SVladimir Kondratyev else 200*f76051c7SVladimir Kondratyev evdev_mt_record_event(evdev, EV_ABS, 201*f76051c7SVladimir Kondratyev ABS_MT_TRACKING_ID, -1); 202*f76051c7SVladimir Kondratyev } else 20305936028SVladimir Kondratyev evdev_mt_send_slot(evdev, slot, state); 20405936028SVladimir Kondratyev EVDEV_EXIT(evdev); 20505936028SVladimir Kondratyev 20605936028SVladimir Kondratyev return (0); 20705936028SVladimir Kondratyev } 20805936028SVladimir Kondratyev 2094c0a134eSVladimir Kondratyev /* 2104c0a134eSVladimir Kondratyev * Find a minimum-weight matching for an m-by-n matrix. 2114c0a134eSVladimir Kondratyev * 2124c0a134eSVladimir Kondratyev * m must be greater than or equal to n. The size of the buffer must be 2134c0a134eSVladimir Kondratyev * at least 3m + 3n. 2144c0a134eSVladimir Kondratyev * 2154c0a134eSVladimir Kondratyev * On return, the first m elements of the buffer contain the row-to- 2164c0a134eSVladimir Kondratyev * column mappings, i.e., buffer[i] is the column index for row i, or -1 2174c0a134eSVladimir Kondratyev * if there is no assignment for that row (which may happen if n < m). 2184c0a134eSVladimir Kondratyev * 2194c0a134eSVladimir Kondratyev * Wrong results because of overflows will not occur with input values 2204c0a134eSVladimir Kondratyev * in the range of 0 to INT_MAX / 2 inclusive. 2214c0a134eSVladimir Kondratyev * 2224c0a134eSVladimir Kondratyev * The function applies the Dinic-Kronrod algorithm. It is not modern or 2234c0a134eSVladimir Kondratyev * popular, but it seems to be a good choice for small matrices at least. 2244c0a134eSVladimir Kondratyev * The original form of the algorithm is modified as follows: There is no 2254c0a134eSVladimir Kondratyev * initial search for row minima, the initial assignments are in a 2264c0a134eSVladimir Kondratyev * "virtual" column with the index -1 and zero values. This permits inputs 2274c0a134eSVladimir Kondratyev * with n < m, and it simplifies the reassignments. 2284c0a134eSVladimir Kondratyev */ 2294c0a134eSVladimir Kondratyev static void 2304c0a134eSVladimir Kondratyev evdev_mt_matching(int *matrix, int m, int n, int *buffer) 2314c0a134eSVladimir Kondratyev { 2324c0a134eSVladimir Kondratyev int i, j, k, d, e, row, col, delta; 2334c0a134eSVladimir Kondratyev int *p; 2344c0a134eSVladimir Kondratyev int *r2c = buffer; /* row-to-column assignments */ 2354c0a134eSVladimir Kondratyev int *red = r2c + m; /* reduced values of the assignments */ 2364c0a134eSVladimir Kondratyev int *mc = red + m; /* row-wise minimal elements of cs */ 2374c0a134eSVladimir Kondratyev int *cs = mc + m; /* the column set */ 2384c0a134eSVladimir Kondratyev int *c2r = cs + n; /* column-to-row assignments in cs */ 2394c0a134eSVladimir Kondratyev int *cd = c2r + n; /* column deltas (reduction) */ 2404c0a134eSVladimir Kondratyev 2414c0a134eSVladimir Kondratyev for (p = r2c; p < red; *p++ = -1) {} 2424c0a134eSVladimir Kondratyev for (; p < mc; *p++ = 0) {} 2434c0a134eSVladimir Kondratyev for (col = 0; col < n; col++) { 2444c0a134eSVladimir Kondratyev delta = INT_MAX; 2454c0a134eSVladimir Kondratyev for (i = 0, p = matrix + col; i < m; i++, p += n) { 2464c0a134eSVladimir Kondratyev d = *p - red[i]; 2474c0a134eSVladimir Kondratyev if (d < delta || (d == delta && r2c[i] < 0)) { 2484c0a134eSVladimir Kondratyev delta = d; 2494c0a134eSVladimir Kondratyev row = i; 2504c0a134eSVladimir Kondratyev } 2514c0a134eSVladimir Kondratyev } 2524c0a134eSVladimir Kondratyev cd[col] = delta; 2534c0a134eSVladimir Kondratyev if (r2c[row] < 0) { 2544c0a134eSVladimir Kondratyev r2c[row] = col; 2554c0a134eSVladimir Kondratyev continue; 2564c0a134eSVladimir Kondratyev } 2574c0a134eSVladimir Kondratyev for (p = mc; p < cs; *p++ = col) {} 2584c0a134eSVladimir Kondratyev for (k = 0; (j = r2c[row]) >= 0;) { 2594c0a134eSVladimir Kondratyev cs[k++] = j; 2604c0a134eSVladimir Kondratyev c2r[j] = row; 2614c0a134eSVladimir Kondratyev mc[row] -= n; 2624c0a134eSVladimir Kondratyev delta = INT_MAX; 2634c0a134eSVladimir Kondratyev for (i = 0, p = matrix; i < m; i++, p += n) 2644c0a134eSVladimir Kondratyev if (mc[i] >= 0) { 2654c0a134eSVladimir Kondratyev d = p[mc[i]] - cd[mc[i]]; 2664c0a134eSVladimir Kondratyev e = p[j] - cd[j]; 2674c0a134eSVladimir Kondratyev if (e < d) { 2684c0a134eSVladimir Kondratyev d = e; 2694c0a134eSVladimir Kondratyev mc[i] = j; 2704c0a134eSVladimir Kondratyev } 2714c0a134eSVladimir Kondratyev d -= red[i]; 2724c0a134eSVladimir Kondratyev if (d < delta || (d == delta 2734c0a134eSVladimir Kondratyev && r2c[i] < 0)) { 2744c0a134eSVladimir Kondratyev delta = d; 2754c0a134eSVladimir Kondratyev row = i; 2764c0a134eSVladimir Kondratyev } 2774c0a134eSVladimir Kondratyev } 2784c0a134eSVladimir Kondratyev cd[col] += delta; 2794c0a134eSVladimir Kondratyev for (i = 0; i < k; i++) { 2804c0a134eSVladimir Kondratyev cd[cs[i]] += delta; 2814c0a134eSVladimir Kondratyev red[c2r[cs[i]]] -= delta; 2824c0a134eSVladimir Kondratyev } 2834c0a134eSVladimir Kondratyev } 2844c0a134eSVladimir Kondratyev for (j = mc[row]; (r2c[row] = j) != col;) { 2854c0a134eSVladimir Kondratyev row = c2r[j]; 2864c0a134eSVladimir Kondratyev j = mc[row] + n; 2874c0a134eSVladimir Kondratyev } 2884c0a134eSVladimir Kondratyev } 2894c0a134eSVladimir Kondratyev } 2904c0a134eSVladimir Kondratyev 2914c0a134eSVladimir Kondratyev /* 2924c0a134eSVladimir Kondratyev * Assign tracking IDs to the points in the pt array. The tracking ID 2934c0a134eSVladimir Kondratyev * assignment pairs the points with points of the previous frame in 2944c0a134eSVladimir Kondratyev * such a way that the sum of the squared distances is minimal. Using 2954c0a134eSVladimir Kondratyev * squares instead of simple distances favours assignments with more uniform 2964c0a134eSVladimir Kondratyev * distances, and it is faster. 2974c0a134eSVladimir Kondratyev * Set tracking id to -1 for unassigned (new) points. 2984c0a134eSVladimir Kondratyev */ 2994c0a134eSVladimir Kondratyev void 3004c0a134eSVladimir Kondratyev evdev_mt_match_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, 3014c0a134eSVladimir Kondratyev int size) 3024c0a134eSVladimir Kondratyev { 3034c0a134eSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 3044c0a134eSVladimir Kondratyev int i, j, m, n, dx, dy, slot, num_touches; 3054c0a134eSVladimir Kondratyev int *p, *r2c, *c2r; 3064c0a134eSVladimir Kondratyev 3074c0a134eSVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev); 3084c0a134eSVladimir Kondratyev MPASS(mt->matrix != NULL); 3094c0a134eSVladimir Kondratyev MPASS(size >= 0 && size <= MAXIMAL_MT_SLOT(evdev) + 1); 3104c0a134eSVladimir Kondratyev 3114c0a134eSVladimir Kondratyev if (size == 0) 3124c0a134eSVladimir Kondratyev return; 3134c0a134eSVladimir Kondratyev 3144c0a134eSVladimir Kondratyev p = mt->matrix; 3154c0a134eSVladimir Kondratyev num_touches = bitcount(mt->touches); 3164c0a134eSVladimir Kondratyev if (num_touches >= size) { 3174c0a134eSVladimir Kondratyev FOREACHBIT(mt->touches, slot) 3184c0a134eSVladimir Kondratyev for (i = 0; i < size; i++) { 3194c0a134eSVladimir Kondratyev dx = pt[i].x - mt->slots[slot].x; 3204c0a134eSVladimir Kondratyev dy = pt[i].y - mt->slots[slot].y; 3214c0a134eSVladimir Kondratyev *p++ = dx * dx + dy * dy; 3224c0a134eSVladimir Kondratyev } 3234c0a134eSVladimir Kondratyev m = num_touches; 3244c0a134eSVladimir Kondratyev n = size; 3254c0a134eSVladimir Kondratyev } else { 3264c0a134eSVladimir Kondratyev for (i = 0; i < size; i++) 3274c0a134eSVladimir Kondratyev FOREACHBIT(mt->touches, slot) { 3284c0a134eSVladimir Kondratyev dx = pt[i].x - mt->slots[slot].x; 3294c0a134eSVladimir Kondratyev dy = pt[i].y - mt->slots[slot].y; 3304c0a134eSVladimir Kondratyev *p++ = dx * dx + dy * dy; 3314c0a134eSVladimir Kondratyev } 3324c0a134eSVladimir Kondratyev m = size; 3334c0a134eSVladimir Kondratyev n = num_touches; 3344c0a134eSVladimir Kondratyev } 3354c0a134eSVladimir Kondratyev evdev_mt_matching(mt->matrix, m, n, p); 3364c0a134eSVladimir Kondratyev 3374c0a134eSVladimir Kondratyev r2c = p; 3384c0a134eSVladimir Kondratyev c2r = p + m; 3394c0a134eSVladimir Kondratyev for (i = 0; i < m; i++) 3404c0a134eSVladimir Kondratyev if ((j = r2c[i]) >= 0) 3414c0a134eSVladimir Kondratyev c2r[j] = i; 3424c0a134eSVladimir Kondratyev 3434c0a134eSVladimir Kondratyev p = (n == size ? c2r : r2c); 3444c0a134eSVladimir Kondratyev for (i = 0; i < size; i++) 3454c0a134eSVladimir Kondratyev if (*p++ < 0) 3464c0a134eSVladimir Kondratyev pt[i].id = -1; 3474c0a134eSVladimir Kondratyev 3484c0a134eSVladimir Kondratyev p = (n == size ? r2c : c2r); 3494c0a134eSVladimir Kondratyev FOREACHBIT(mt->touches, slot) 3504c0a134eSVladimir Kondratyev if ((i = *p++) >= 0) 3514c0a134eSVladimir Kondratyev pt[i].id = mt->tracking_ids[slot]; 3524c0a134eSVladimir Kondratyev } 3534c0a134eSVladimir Kondratyev 3544c0a134eSVladimir Kondratyev static void 3554c0a134eSVladimir Kondratyev evdev_mt_send_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, int size) 3564c0a134eSVladimir Kondratyev { 3574c0a134eSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 3584c0a134eSVladimir Kondratyev union evdev_mt_slot *slot; 3594c0a134eSVladimir Kondratyev 3604c0a134eSVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev); 3614c0a134eSVladimir Kondratyev MPASS(size >= 0 && size <= MAXIMAL_MT_SLOT(evdev) + 1); 3624c0a134eSVladimir Kondratyev 3634c0a134eSVladimir Kondratyev /* 3644c0a134eSVladimir Kondratyev * While MT-matching assign tracking IDs of new contacts to be equal 3654c0a134eSVladimir Kondratyev * to a slot number to make things simpler. 3664c0a134eSVladimir Kondratyev */ 3674c0a134eSVladimir Kondratyev for (slot = pt; slot < pt + size; slot++) { 3684c0a134eSVladimir Kondratyev if (slot->id < 0) 3694c0a134eSVladimir Kondratyev slot->id = ffc_slot(evdev, mt->touches | mt->frame); 3704c0a134eSVladimir Kondratyev if (slot->id >= 0) 3714c0a134eSVladimir Kondratyev evdev_mt_send_slot(evdev, slot->id, slot); 3724c0a134eSVladimir Kondratyev } 3734c0a134eSVladimir Kondratyev } 3744c0a134eSVladimir Kondratyev 3754c0a134eSVladimir Kondratyev int 3764c0a134eSVladimir Kondratyev evdev_mt_push_frame(struct evdev_dev *evdev, union evdev_mt_slot *pt, int size) 3774c0a134eSVladimir Kondratyev { 3784c0a134eSVladimir Kondratyev if (size < 0 || size > MAXIMAL_MT_SLOT(evdev) + 1) 3794c0a134eSVladimir Kondratyev return (EINVAL); 3804c0a134eSVladimir Kondratyev 3814c0a134eSVladimir Kondratyev EVDEV_ENTER(evdev); 3824c0a134eSVladimir Kondratyev evdev_mt_send_frame(evdev, pt, size); 3834c0a134eSVladimir Kondratyev EVDEV_EXIT(evdev); 3844c0a134eSVladimir Kondratyev 3854c0a134eSVladimir Kondratyev return (0); 3864c0a134eSVladimir Kondratyev } 3874c0a134eSVladimir Kondratyev 388*f76051c7SVladimir Kondratyev bool 389*f76051c7SVladimir Kondratyev evdev_mt_record_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, 390*f76051c7SVladimir Kondratyev int32_t value) 391*f76051c7SVladimir Kondratyev { 392*f76051c7SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 393*f76051c7SVladimir Kondratyev 394*f76051c7SVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev); 395*f76051c7SVladimir Kondratyev 396*f76051c7SVladimir Kondratyev switch (type) { 397*f76051c7SVladimir Kondratyev case EV_ABS: 398*f76051c7SVladimir Kondratyev if (code == ABS_MT_SLOT) { 399*f76051c7SVladimir Kondratyev /* MT protocol type B support */ 400*f76051c7SVladimir Kondratyev KASSERT(value >= 0, ("Negative slot number")); 401*f76051c7SVladimir Kondratyev mt->match_slot = value; 402*f76051c7SVladimir Kondratyev mt->match_frame |= 1U << mt->match_slot; 403*f76051c7SVladimir Kondratyev return (true); 404*f76051c7SVladimir Kondratyev } else if (code == ABS_MT_TRACKING_ID) { 405*f76051c7SVladimir Kondratyev if (value == -1) 406*f76051c7SVladimir Kondratyev mt->match_frame &= ~(1U << mt->match_slot); 407*f76051c7SVladimir Kondratyev return (true); 408*f76051c7SVladimir Kondratyev } else if (ABS_IS_MT(code)) { 409*f76051c7SVladimir Kondratyev KASSERT(mt->match_slot >= 0, ("Negative slot")); 410*f76051c7SVladimir Kondratyev KASSERT(mt->match_slot <= MAXIMAL_MT_SLOT(evdev), 411*f76051c7SVladimir Kondratyev ("Slot number too big")); 412*f76051c7SVladimir Kondratyev mt->match_slots[mt->match_slot]. 413*f76051c7SVladimir Kondratyev val[ABS_MT_INDEX(code)] = value; 414*f76051c7SVladimir Kondratyev return (true); 415*f76051c7SVladimir Kondratyev } 416*f76051c7SVladimir Kondratyev break; 417*f76051c7SVladimir Kondratyev default: 418*f76051c7SVladimir Kondratyev break; 419*f76051c7SVladimir Kondratyev } 420*f76051c7SVladimir Kondratyev 421*f76051c7SVladimir Kondratyev return (false); 422*f76051c7SVladimir Kondratyev } 423*f76051c7SVladimir Kondratyev 424*f76051c7SVladimir Kondratyev static void 425*f76051c7SVladimir Kondratyev evdev_mt_replay_events(struct evdev_dev *evdev) 426*f76051c7SVladimir Kondratyev { 427*f76051c7SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 428*f76051c7SVladimir Kondratyev int slot, size = 0; 429*f76051c7SVladimir Kondratyev 430*f76051c7SVladimir Kondratyev EVDEV_LOCK_ASSERT(evdev); 431*f76051c7SVladimir Kondratyev 432*f76051c7SVladimir Kondratyev FOREACHBIT(mt->match_frame, slot) { 433*f76051c7SVladimir Kondratyev if (slot != size) 434*f76051c7SVladimir Kondratyev mt->match_slots[size] = mt->match_slots[slot]; 435*f76051c7SVladimir Kondratyev size++; 436*f76051c7SVladimir Kondratyev } 437*f76051c7SVladimir Kondratyev evdev_mt_match_frame(evdev, mt->match_slots, size); 438*f76051c7SVladimir Kondratyev evdev_mt_send_frame(evdev, mt->match_slots, size); 439*f76051c7SVladimir Kondratyev mt->match_slot = 0; 440*f76051c7SVladimir Kondratyev mt->match_frame = 0; 441*f76051c7SVladimir Kondratyev } 442*f76051c7SVladimir Kondratyev 443*f76051c7SVladimir Kondratyev union evdev_mt_slot * 444*f76051c7SVladimir Kondratyev evdev_mt_get_match_slots(struct evdev_dev *evdev) 445*f76051c7SVladimir Kondratyev { 446*f76051c7SVladimir Kondratyev return (evdev->ev_mt->match_slots); 447*f76051c7SVladimir Kondratyev } 448*f76051c7SVladimir Kondratyev 44998a7606bSVladimir Kondratyev int 45098a7606bSVladimir Kondratyev evdev_mt_get_last_slot(struct evdev_dev *evdev) 45198a7606bSVladimir Kondratyev { 45298a7606bSVladimir Kondratyev return (evdev->ev_mt->last_reported_slot); 4532b3f6d66SOleksandr Tymoshenko } 4542b3f6d66SOleksandr Tymoshenko 4552b3f6d66SOleksandr Tymoshenko void 45698a7606bSVladimir Kondratyev evdev_mt_set_last_slot(struct evdev_dev *evdev, int slot) 4572b3f6d66SOleksandr Tymoshenko { 45898a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 4592b3f6d66SOleksandr Tymoshenko 46098a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 4612b3f6d66SOleksandr Tymoshenko 4622dc7188eSVladimir Kondratyev mt->frame |= 1U << slot; 46398a7606bSVladimir Kondratyev mt->last_reported_slot = slot; 4642b3f6d66SOleksandr Tymoshenko } 4652b3f6d66SOleksandr Tymoshenko 4662b3f6d66SOleksandr Tymoshenko int32_t 46798a7606bSVladimir Kondratyev evdev_mt_get_value(struct evdev_dev *evdev, int slot, int16_t code) 46898a7606bSVladimir Kondratyev { 46998a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 47098a7606bSVladimir Kondratyev 47198a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 47298a7606bSVladimir Kondratyev 47398a7606bSVladimir Kondratyev return (mt->slots[slot].val[ABS_MT_INDEX(code)]); 47498a7606bSVladimir Kondratyev } 47598a7606bSVladimir Kondratyev 47698a7606bSVladimir Kondratyev void 47798a7606bSVladimir Kondratyev evdev_mt_set_value(struct evdev_dev *evdev, int slot, int16_t code, 47898a7606bSVladimir Kondratyev int32_t value) 47998a7606bSVladimir Kondratyev { 48098a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 48198a7606bSVladimir Kondratyev 48298a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 48398a7606bSVladimir Kondratyev 4842dc7188eSVladimir Kondratyev if (code == ABS_MT_TRACKING_ID) { 4852dc7188eSVladimir Kondratyev if (value != -1) 4862dc7188eSVladimir Kondratyev mt->touches |= 1U << slot; 4872dc7188eSVladimir Kondratyev else 4882dc7188eSVladimir Kondratyev mt->touches &= ~(1U << slot); 4892dc7188eSVladimir Kondratyev } 49098a7606bSVladimir Kondratyev mt->slots[slot].val[ABS_MT_INDEX(code)] = value; 49198a7606bSVladimir Kondratyev } 49298a7606bSVladimir Kondratyev 49398a7606bSVladimir Kondratyev int 4942b3f6d66SOleksandr Tymoshenko evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id) 4952b3f6d66SOleksandr Tymoshenko { 49698a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 4972dc7188eSVladimir Kondratyev int slot; 4982b3f6d66SOleksandr Tymoshenko 499*f76051c7SVladimir Kondratyev /* 500*f76051c7SVladimir Kondratyev * Ignore tracking_id if slot assignment is performed by evdev. 501*f76051c7SVladimir Kondratyev * Events are written sequentially to temporary matching buffer. 502*f76051c7SVladimir Kondratyev */ 503*f76051c7SVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_TRACK)) 504*f76051c7SVladimir Kondratyev return (ffc_slot(evdev, mt->match_frame)); 505*f76051c7SVladimir Kondratyev 5062dc7188eSVladimir Kondratyev FOREACHBIT(mt->touches, slot) 50766bd52f5SVladimir Kondratyev if (mt->tracking_ids[slot] == tracking_id) 5082b3f6d66SOleksandr Tymoshenko return (slot); 5092b3f6d66SOleksandr Tymoshenko /* 5102dc7188eSVladimir Kondratyev * Do not allow allocation of new slot in a place of just 5112dc7188eSVladimir Kondratyev * released one within the same report. 5122b3f6d66SOleksandr Tymoshenko */ 5132dc7188eSVladimir Kondratyev return (ffc_slot(evdev, mt->touches | mt->frame)); 5142b3f6d66SOleksandr Tymoshenko } 5152b3f6d66SOleksandr Tymoshenko 51666bd52f5SVladimir Kondratyev int32_t 51766bd52f5SVladimir Kondratyev evdev_mt_reassign_id(struct evdev_dev *evdev, int slot, int32_t id) 51866bd52f5SVladimir Kondratyev { 51966bd52f5SVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 52066bd52f5SVladimir Kondratyev int32_t nid; 52166bd52f5SVladimir Kondratyev 52266bd52f5SVladimir Kondratyev if (id == -1 || bit_test(evdev->ev_flags, EVDEV_FLAG_MT_KEEPID)) { 52366bd52f5SVladimir Kondratyev mt->tracking_ids[slot] = id; 52466bd52f5SVladimir Kondratyev return (id); 52566bd52f5SVladimir Kondratyev } 52666bd52f5SVladimir Kondratyev 52766bd52f5SVladimir Kondratyev nid = evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID); 52866bd52f5SVladimir Kondratyev if (nid != -1) { 52966bd52f5SVladimir Kondratyev KASSERT(id == mt->tracking_ids[slot], 53066bd52f5SVladimir Kondratyev ("MT-slot tracking id has changed")); 53166bd52f5SVladimir Kondratyev return (nid); 53266bd52f5SVladimir Kondratyev } 53366bd52f5SVladimir Kondratyev 53466bd52f5SVladimir Kondratyev mt->tracking_ids[slot] = id; 53566bd52f5SVladimir Kondratyev again: 53666bd52f5SVladimir Kondratyev nid = mt->tracking_id++; 53766bd52f5SVladimir Kondratyev FOREACHBIT(mt->touches, slot) 53866bd52f5SVladimir Kondratyev if (evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID) == nid) 53966bd52f5SVladimir Kondratyev goto again; 54066bd52f5SVladimir Kondratyev 54166bd52f5SVladimir Kondratyev return (nid); 54266bd52f5SVladimir Kondratyev } 54366bd52f5SVladimir Kondratyev 544127e54deSVladimir Kondratyev static inline int32_t 545127e54deSVladimir Kondratyev evdev_mt_normalize(int32_t value, int32_t mtmin, int32_t mtmax, int32_t stmax) 546127e54deSVladimir Kondratyev { 547127e54deSVladimir Kondratyev if (stmax != 0 && mtmax != mtmin) { 548127e54deSVladimir Kondratyev value = (value - mtmin) * stmax / (mtmax - mtmin); 549127e54deSVladimir Kondratyev value = MAX(MIN(value, stmax), 0); 550127e54deSVladimir Kondratyev } 551127e54deSVladimir Kondratyev return (value); 552127e54deSVladimir Kondratyev } 553127e54deSVladimir Kondratyev 5542b3f6d66SOleksandr Tymoshenko void 5552b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(struct evdev_dev *evdev) 5562b3f6d66SOleksandr Tymoshenko { 557127e54deSVladimir Kondratyev struct input_absinfo *ai; 55898a7606bSVladimir Kondratyev int i; 5592b3f6d66SOleksandr Tymoshenko 5602b3f6d66SOleksandr Tymoshenko if (evdev->ev_absinfo == NULL) 5612b3f6d66SOleksandr Tymoshenko return; 5622b3f6d66SOleksandr Tymoshenko 5632b3f6d66SOleksandr Tymoshenko evdev_support_event(evdev, EV_KEY); 5642b3f6d66SOleksandr Tymoshenko evdev_support_key(evdev, BTN_TOUCH); 5652b3f6d66SOleksandr Tymoshenko 5662b3f6d66SOleksandr Tymoshenko /* Touchscreens should not advertise tap tool capabilities */ 5672b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 5682b3f6d66SOleksandr Tymoshenko evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1); 5692b3f6d66SOleksandr Tymoshenko 5702b3f6d66SOleksandr Tymoshenko /* Echo 0-th MT-slot as ST-slot */ 571127e54deSVladimir Kondratyev for (i = 0; i < nitems(evdev_mtstmap); i++) { 572127e54deSVladimir Kondratyev if (!bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].mt) || 573127e54deSVladimir Kondratyev bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].st)) 574127e54deSVladimir Kondratyev continue; 575127e54deSVladimir Kondratyev ai = evdev->ev_absinfo + evdev_mtstmap[i].mt; 576127e54deSVladimir Kondratyev evdev->ev_mt->mtst_events |= 1U << i; 577127e54deSVladimir Kondratyev if (evdev_mtstmap[i].max != 0) 578127e54deSVladimir Kondratyev evdev_support_abs(evdev, evdev_mtstmap[i].st, 579314913edSVladimir Kondratyev 0, 580127e54deSVladimir Kondratyev evdev_mtstmap[i].max, 581127e54deSVladimir Kondratyev 0, 582127e54deSVladimir Kondratyev evdev_mt_normalize( 583127e54deSVladimir Kondratyev ai->flat, 0, ai->maximum, evdev_mtstmap[i].max), 584127e54deSVladimir Kondratyev 0); 585127e54deSVladimir Kondratyev else 586127e54deSVladimir Kondratyev evdev_support_abs(evdev, evdev_mtstmap[i].st, 587127e54deSVladimir Kondratyev ai->minimum, 588127e54deSVladimir Kondratyev ai->maximum, 589127e54deSVladimir Kondratyev 0, 590127e54deSVladimir Kondratyev ai->flat, 591127e54deSVladimir Kondratyev ai->resolution); 592127e54deSVladimir Kondratyev } 5932b3f6d66SOleksandr Tymoshenko } 5942b3f6d66SOleksandr Tymoshenko 5952b3f6d66SOleksandr Tymoshenko static void 59698a7606bSVladimir Kondratyev evdev_mt_send_st_compat(struct evdev_dev *evdev) 5972b3f6d66SOleksandr Tymoshenko { 5982dc7188eSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 599fbe17f90SVladimir Kondratyev int nfingers, i, st_slot; 6002b3f6d66SOleksandr Tymoshenko 6012b3f6d66SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 6022b3f6d66SOleksandr Tymoshenko 6032dc7188eSVladimir Kondratyev nfingers = bitcount(mt->touches); 6042b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0); 6052b3f6d66SOleksandr Tymoshenko 606fbe17f90SVladimir Kondratyev /* Send first active MT-slot state as single touch report */ 607fbe17f90SVladimir Kondratyev st_slot = ffs(mt->touches) - 1; 608fbe17f90SVladimir Kondratyev if (st_slot != -1) 609127e54deSVladimir Kondratyev FOREACHBIT(mt->mtst_events, i) 610127e54deSVladimir Kondratyev evdev_send_event(evdev, EV_ABS, evdev_mtstmap[i].st, 611127e54deSVladimir Kondratyev evdev_mt_normalize(evdev_mt_get_value(evdev, 612127e54deSVladimir Kondratyev st_slot, evdev_mtstmap[i].mt), 613127e54deSVladimir Kondratyev evdev->ev_absinfo[evdev_mtstmap[i].mt].minimum, 614127e54deSVladimir Kondratyev evdev->ev_absinfo[evdev_mtstmap[i].mt].maximum, 615127e54deSVladimir Kondratyev evdev_mtstmap[i].max)); 6162b3f6d66SOleksandr Tymoshenko 6172b3f6d66SOleksandr Tymoshenko /* Touchscreens should not report tool taps */ 6182b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 6192b3f6d66SOleksandr Tymoshenko evdev_send_nfingers(evdev, nfingers); 6202b3f6d66SOleksandr Tymoshenko 6212b3f6d66SOleksandr Tymoshenko if (nfingers == 0) 6222b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0); 6232b3f6d66SOleksandr Tymoshenko } 6242b3f6d66SOleksandr Tymoshenko 6252b3f6d66SOleksandr Tymoshenko void 6262b3f6d66SOleksandr Tymoshenko evdev_push_mt_compat(struct evdev_dev *evdev) 6272b3f6d66SOleksandr Tymoshenko { 6282b3f6d66SOleksandr Tymoshenko 6294c0a4665SVladimir Kondratyev EVDEV_ENTER(evdev); 63098a7606bSVladimir Kondratyev evdev_mt_send_st_compat(evdev); 6314c0a4665SVladimir Kondratyev EVDEV_EXIT(evdev); 6322b3f6d66SOleksandr Tymoshenko } 633c736a757SOleksandr Tymoshenko 63498a7606bSVladimir Kondratyev static void 63598a7606bSVladimir Kondratyev evdev_mt_send_autorel(struct evdev_dev *evdev) 636c736a757SOleksandr Tymoshenko { 63798a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 63898a7606bSVladimir Kondratyev int slot; 639c736a757SOleksandr Tymoshenko 640c736a757SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 641*f76051c7SVladimir Kondratyev KASSERT(mt->match_frame == 0, ("Unmatched events exist")); 642c736a757SOleksandr Tymoshenko 64305936028SVladimir Kondratyev FOREACHBIT(mt->touches & ~mt->frame, slot) 64405936028SVladimir Kondratyev evdev_mt_send_slot(evdev, slot, NULL); 645c736a757SOleksandr Tymoshenko } 64698a7606bSVladimir Kondratyev 64798a7606bSVladimir Kondratyev void 64898a7606bSVladimir Kondratyev evdev_mt_push_autorel(struct evdev_dev *evdev) 64998a7606bSVladimir Kondratyev { 65098a7606bSVladimir Kondratyev EVDEV_ENTER(evdev); 65198a7606bSVladimir Kondratyev evdev_mt_send_autorel(evdev); 65298a7606bSVladimir Kondratyev EVDEV_EXIT(evdev); 65398a7606bSVladimir Kondratyev } 654