12b3f6d66SOleksandr Tymoshenko /*- 22b3f6d66SOleksandr Tymoshenko * Copyright (c) 2016 Vladimir Kondratyev <wulf@cicgroup.ru> 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 */ 282b3f6d66SOleksandr Tymoshenko 292b3f6d66SOleksandr Tymoshenko #include <sys/param.h> 302b3f6d66SOleksandr Tymoshenko #include <sys/malloc.h> 312b3f6d66SOleksandr Tymoshenko #include <sys/lock.h> 322b3f6d66SOleksandr Tymoshenko #include <sys/mutex.h> 332b3f6d66SOleksandr Tymoshenko #include <sys/systm.h> 342b3f6d66SOleksandr Tymoshenko 352b3f6d66SOleksandr Tymoshenko #include <dev/evdev/input.h> 362b3f6d66SOleksandr Tymoshenko #include <dev/evdev/evdev.h> 372b3f6d66SOleksandr Tymoshenko #include <dev/evdev/evdev_private.h> 382b3f6d66SOleksandr Tymoshenko 392b3f6d66SOleksandr Tymoshenko #ifdef DEBUG 402b3f6d66SOleksandr Tymoshenko #define debugf(fmt, args...) printf("evdev: " fmt "\n", ##args) 412b3f6d66SOleksandr Tymoshenko #else 422b3f6d66SOleksandr Tymoshenko #define debugf(fmt, args...) 432b3f6d66SOleksandr Tymoshenko #endif 442b3f6d66SOleksandr Tymoshenko 452b3f6d66SOleksandr Tymoshenko static uint16_t evdev_fngmap[] = { 462b3f6d66SOleksandr Tymoshenko BTN_TOOL_FINGER, 472b3f6d66SOleksandr Tymoshenko BTN_TOOL_DOUBLETAP, 482b3f6d66SOleksandr Tymoshenko BTN_TOOL_TRIPLETAP, 492b3f6d66SOleksandr Tymoshenko BTN_TOOL_QUADTAP, 502b3f6d66SOleksandr Tymoshenko BTN_TOOL_QUINTTAP, 512b3f6d66SOleksandr Tymoshenko }; 522b3f6d66SOleksandr Tymoshenko 532b3f6d66SOleksandr Tymoshenko static uint16_t evdev_mtstmap[][2] = { 542b3f6d66SOleksandr Tymoshenko { ABS_MT_POSITION_X, ABS_X }, 552b3f6d66SOleksandr Tymoshenko { ABS_MT_POSITION_Y, ABS_Y }, 562b3f6d66SOleksandr Tymoshenko { ABS_MT_PRESSURE, ABS_PRESSURE }, 572b3f6d66SOleksandr Tymoshenko { ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH }, 582b3f6d66SOleksandr Tymoshenko }; 592b3f6d66SOleksandr Tymoshenko 602b3f6d66SOleksandr Tymoshenko struct evdev_mt_slot { 612b3f6d66SOleksandr Tymoshenko uint64_t ev_report; 622b3f6d66SOleksandr Tymoshenko int32_t ev_mt_states[MT_CNT]; 632b3f6d66SOleksandr Tymoshenko }; 642b3f6d66SOleksandr Tymoshenko 652b3f6d66SOleksandr Tymoshenko struct evdev_mt { 662b3f6d66SOleksandr Tymoshenko int32_t ev_mt_last_reported_slot; 672b3f6d66SOleksandr Tymoshenko struct evdev_mt_slot ev_mt_slots[]; 682b3f6d66SOleksandr Tymoshenko }; 692b3f6d66SOleksandr Tymoshenko 702b3f6d66SOleksandr Tymoshenko void 712b3f6d66SOleksandr Tymoshenko evdev_mt_init(struct evdev_dev *evdev) 722b3f6d66SOleksandr Tymoshenko { 732b3f6d66SOleksandr Tymoshenko int32_t slot, slots; 742b3f6d66SOleksandr Tymoshenko 752b3f6d66SOleksandr Tymoshenko slots = MAXIMAL_MT_SLOT(evdev) + 1; 762b3f6d66SOleksandr Tymoshenko 772b3f6d66SOleksandr Tymoshenko evdev->ev_mt = malloc(offsetof(struct evdev_mt, ev_mt_slots) + 782b3f6d66SOleksandr Tymoshenko sizeof(struct evdev_mt_slot) * slots, M_EVDEV, M_WAITOK | M_ZERO); 792b3f6d66SOleksandr Tymoshenko 802b3f6d66SOleksandr Tymoshenko /* Initialize multitouch protocol type B states */ 812b3f6d66SOleksandr Tymoshenko for (slot = 0; slot < slots; slot++) { 822b3f6d66SOleksandr Tymoshenko /* 832b3f6d66SOleksandr Tymoshenko * .ev_report should not be initialized to initial value of 842b3f6d66SOleksandr Tymoshenko * report counter (0) as it brokes free slot detection in 852b3f6d66SOleksandr Tymoshenko * evdev_get_mt_slot_by_tracking_id. So initialize it to -1 862b3f6d66SOleksandr Tymoshenko */ 872b3f6d66SOleksandr Tymoshenko evdev->ev_mt->ev_mt_slots[slot] = (struct evdev_mt_slot) { 882b3f6d66SOleksandr Tymoshenko .ev_report = 0xFFFFFFFFFFFFFFFFULL, 892b3f6d66SOleksandr Tymoshenko .ev_mt_states[ABS_MT_INDEX(ABS_MT_TRACKING_ID)] = -1, 902b3f6d66SOleksandr Tymoshenko }; 912b3f6d66SOleksandr Tymoshenko } 922b3f6d66SOleksandr Tymoshenko 932b3f6d66SOleksandr Tymoshenko if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) 942b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(evdev); 952b3f6d66SOleksandr Tymoshenko } 962b3f6d66SOleksandr Tymoshenko 972b3f6d66SOleksandr Tymoshenko void 982b3f6d66SOleksandr Tymoshenko evdev_mt_free(struct evdev_dev *evdev) 992b3f6d66SOleksandr Tymoshenko { 1002b3f6d66SOleksandr Tymoshenko 1012b3f6d66SOleksandr Tymoshenko free(evdev->ev_mt, M_EVDEV); 1022b3f6d66SOleksandr Tymoshenko } 1032b3f6d66SOleksandr Tymoshenko 1042b3f6d66SOleksandr Tymoshenko int32_t 1052b3f6d66SOleksandr Tymoshenko evdev_get_last_mt_slot(struct evdev_dev *evdev) 1062b3f6d66SOleksandr Tymoshenko { 1072b3f6d66SOleksandr Tymoshenko 1082b3f6d66SOleksandr Tymoshenko return (evdev->ev_mt->ev_mt_last_reported_slot); 1092b3f6d66SOleksandr Tymoshenko } 1102b3f6d66SOleksandr Tymoshenko 1112b3f6d66SOleksandr Tymoshenko void 1122b3f6d66SOleksandr Tymoshenko evdev_set_last_mt_slot(struct evdev_dev *evdev, int32_t slot) 1132b3f6d66SOleksandr Tymoshenko { 1142b3f6d66SOleksandr Tymoshenko 115*c736a757SOleksandr Tymoshenko evdev->ev_mt->ev_mt_slots[slot].ev_report = evdev->ev_report_count; 1162b3f6d66SOleksandr Tymoshenko evdev->ev_mt->ev_mt_last_reported_slot = slot; 1172b3f6d66SOleksandr Tymoshenko } 1182b3f6d66SOleksandr Tymoshenko 1192b3f6d66SOleksandr Tymoshenko inline int32_t 1202b3f6d66SOleksandr Tymoshenko evdev_get_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code) 1212b3f6d66SOleksandr Tymoshenko { 1222b3f6d66SOleksandr Tymoshenko 1232b3f6d66SOleksandr Tymoshenko return (evdev->ev_mt-> 1242b3f6d66SOleksandr Tymoshenko ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)]); 1252b3f6d66SOleksandr Tymoshenko } 1262b3f6d66SOleksandr Tymoshenko 1272b3f6d66SOleksandr Tymoshenko inline void 1282b3f6d66SOleksandr Tymoshenko evdev_set_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code, 1292b3f6d66SOleksandr Tymoshenko int32_t value) 1302b3f6d66SOleksandr Tymoshenko { 1312b3f6d66SOleksandr Tymoshenko 1322b3f6d66SOleksandr Tymoshenko evdev->ev_mt->ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)] = 1332b3f6d66SOleksandr Tymoshenko value; 1342b3f6d66SOleksandr Tymoshenko } 1352b3f6d66SOleksandr Tymoshenko 1362b3f6d66SOleksandr Tymoshenko int32_t 1372b3f6d66SOleksandr Tymoshenko evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id) 1382b3f6d66SOleksandr Tymoshenko { 1392b3f6d66SOleksandr Tymoshenko int32_t tr_id, slot, free_slot = -1; 1402b3f6d66SOleksandr Tymoshenko 1412b3f6d66SOleksandr Tymoshenko for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) { 1422b3f6d66SOleksandr Tymoshenko tr_id = evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID); 1432b3f6d66SOleksandr Tymoshenko if (tr_id == tracking_id) 1442b3f6d66SOleksandr Tymoshenko return (slot); 1452b3f6d66SOleksandr Tymoshenko /* 1462b3f6d66SOleksandr Tymoshenko * Its possible that slot will be reassigned in a place of just 1472b3f6d66SOleksandr Tymoshenko * released one within the same report. To avoid this compare 1482b3f6d66SOleksandr Tymoshenko * report counter with slot`s report number updated with each 1492b3f6d66SOleksandr Tymoshenko * ABS_MT_TRACKING_ID change. 1502b3f6d66SOleksandr Tymoshenko */ 1512b3f6d66SOleksandr Tymoshenko if (free_slot == -1 && tr_id == -1 && 1522b3f6d66SOleksandr Tymoshenko evdev->ev_mt->ev_mt_slots[slot].ev_report != 1532b3f6d66SOleksandr Tymoshenko evdev->ev_report_count) 1542b3f6d66SOleksandr Tymoshenko free_slot = slot; 1552b3f6d66SOleksandr Tymoshenko } 1562b3f6d66SOleksandr Tymoshenko 1572b3f6d66SOleksandr Tymoshenko return (free_slot); 1582b3f6d66SOleksandr Tymoshenko } 1592b3f6d66SOleksandr Tymoshenko 1602b3f6d66SOleksandr Tymoshenko void 1612b3f6d66SOleksandr Tymoshenko evdev_support_nfingers(struct evdev_dev *evdev, int32_t nfingers) 1622b3f6d66SOleksandr Tymoshenko { 1632b3f6d66SOleksandr Tymoshenko int32_t i; 1642b3f6d66SOleksandr Tymoshenko 1652b3f6d66SOleksandr Tymoshenko for (i = 0; i < MIN(nitems(evdev_fngmap), nfingers); i++) 1662b3f6d66SOleksandr Tymoshenko evdev_support_key(evdev, evdev_fngmap[i]); 1672b3f6d66SOleksandr Tymoshenko } 1682b3f6d66SOleksandr Tymoshenko 1692b3f6d66SOleksandr Tymoshenko void 1702b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(struct evdev_dev *evdev) 1712b3f6d66SOleksandr Tymoshenko { 1722b3f6d66SOleksandr Tymoshenko int32_t i; 1732b3f6d66SOleksandr Tymoshenko 1742b3f6d66SOleksandr Tymoshenko if (evdev->ev_absinfo == NULL) 1752b3f6d66SOleksandr Tymoshenko return; 1762b3f6d66SOleksandr Tymoshenko 1772b3f6d66SOleksandr Tymoshenko evdev_support_event(evdev, EV_KEY); 1782b3f6d66SOleksandr Tymoshenko evdev_support_key(evdev, BTN_TOUCH); 1792b3f6d66SOleksandr Tymoshenko 1802b3f6d66SOleksandr Tymoshenko /* Touchscreens should not advertise tap tool capabilities */ 1812b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 1822b3f6d66SOleksandr Tymoshenko evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1); 1832b3f6d66SOleksandr Tymoshenko 1842b3f6d66SOleksandr Tymoshenko /* Echo 0-th MT-slot as ST-slot */ 1852b3f6d66SOleksandr Tymoshenko for (i = 0; i < nitems(evdev_mtstmap); i++) 1862b3f6d66SOleksandr Tymoshenko if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][0])) 1872b3f6d66SOleksandr Tymoshenko evdev_support_abs(evdev, evdev_mtstmap[i][1], 1882b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].value, 1892b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].minimum, 1902b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].maximum, 1912b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].fuzz, 1922b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].flat, 1932b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].resolution); 1942b3f6d66SOleksandr Tymoshenko } 1952b3f6d66SOleksandr Tymoshenko 1962b3f6d66SOleksandr Tymoshenko static int32_t 1972b3f6d66SOleksandr Tymoshenko evdev_count_fingers(struct evdev_dev *evdev) 1982b3f6d66SOleksandr Tymoshenko { 1992b3f6d66SOleksandr Tymoshenko int32_t nfingers = 0, i; 2002b3f6d66SOleksandr Tymoshenko 2012b3f6d66SOleksandr Tymoshenko for (i = 0; i <= MAXIMAL_MT_SLOT(evdev); i++) 2022b3f6d66SOleksandr Tymoshenko if (evdev_get_mt_value(evdev, i, ABS_MT_TRACKING_ID) != -1) 2032b3f6d66SOleksandr Tymoshenko nfingers++; 2042b3f6d66SOleksandr Tymoshenko 2052b3f6d66SOleksandr Tymoshenko return (nfingers); 2062b3f6d66SOleksandr Tymoshenko } 2072b3f6d66SOleksandr Tymoshenko 2082b3f6d66SOleksandr Tymoshenko static void 2092b3f6d66SOleksandr Tymoshenko evdev_send_nfingers(struct evdev_dev *evdev, int32_t nfingers) 2102b3f6d66SOleksandr Tymoshenko { 2112b3f6d66SOleksandr Tymoshenko int32_t i; 2122b3f6d66SOleksandr Tymoshenko 2132b3f6d66SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 2142b3f6d66SOleksandr Tymoshenko 2152b3f6d66SOleksandr Tymoshenko if (nfingers > nitems(evdev_fngmap)) 2162b3f6d66SOleksandr Tymoshenko nfingers = nitems(evdev_fngmap); 2172b3f6d66SOleksandr Tymoshenko 2182b3f6d66SOleksandr Tymoshenko for (i = 0; i < nitems(evdev_fngmap); i++) 2192b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_KEY, evdev_fngmap[i], 2202b3f6d66SOleksandr Tymoshenko nfingers == i + 1); 2212b3f6d66SOleksandr Tymoshenko } 2222b3f6d66SOleksandr Tymoshenko 2232b3f6d66SOleksandr Tymoshenko void 2242b3f6d66SOleksandr Tymoshenko evdev_push_nfingers(struct evdev_dev *evdev, int32_t nfingers) 2252b3f6d66SOleksandr Tymoshenko { 2262b3f6d66SOleksandr Tymoshenko 227bfbd1bb7SOleksandr Tymoshenko if (evdev->ev_lock_type == EV_LOCK_INTERNAL) 2282b3f6d66SOleksandr Tymoshenko EVDEV_LOCK(evdev); 229bfbd1bb7SOleksandr Tymoshenko else 230bfbd1bb7SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 2312b3f6d66SOleksandr Tymoshenko evdev_send_nfingers(evdev, nfingers); 232bfbd1bb7SOleksandr Tymoshenko if (evdev->ev_lock_type == EV_LOCK_INTERNAL) 2332b3f6d66SOleksandr Tymoshenko EVDEV_UNLOCK(evdev); 2342b3f6d66SOleksandr Tymoshenko } 2352b3f6d66SOleksandr Tymoshenko 2362b3f6d66SOleksandr Tymoshenko void 2372b3f6d66SOleksandr Tymoshenko evdev_send_mt_compat(struct evdev_dev *evdev) 2382b3f6d66SOleksandr Tymoshenko { 2392b3f6d66SOleksandr Tymoshenko int32_t nfingers, i; 2402b3f6d66SOleksandr Tymoshenko 2412b3f6d66SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 2422b3f6d66SOleksandr Tymoshenko 2432b3f6d66SOleksandr Tymoshenko nfingers = evdev_count_fingers(evdev); 2442b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0); 2452b3f6d66SOleksandr Tymoshenko 2462b3f6d66SOleksandr Tymoshenko if (evdev_get_mt_value(evdev, 0, ABS_MT_TRACKING_ID) != -1) 2472b3f6d66SOleksandr Tymoshenko /* Echo 0-th MT-slot as ST-slot */ 2482b3f6d66SOleksandr Tymoshenko for (i = 0; i < nitems(evdev_mtstmap); i++) 2492b3f6d66SOleksandr Tymoshenko if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][1])) 2502b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, 2512b3f6d66SOleksandr Tymoshenko evdev_mtstmap[i][1], 2522b3f6d66SOleksandr Tymoshenko evdev_get_mt_value(evdev, 0, 2532b3f6d66SOleksandr Tymoshenko evdev_mtstmap[i][0])); 2542b3f6d66SOleksandr Tymoshenko 2552b3f6d66SOleksandr Tymoshenko /* Touchscreens should not report tool taps */ 2562b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 2572b3f6d66SOleksandr Tymoshenko evdev_send_nfingers(evdev, nfingers); 2582b3f6d66SOleksandr Tymoshenko 2592b3f6d66SOleksandr Tymoshenko if (nfingers == 0) 2602b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0); 2612b3f6d66SOleksandr Tymoshenko } 2622b3f6d66SOleksandr Tymoshenko 2632b3f6d66SOleksandr Tymoshenko void 2642b3f6d66SOleksandr Tymoshenko evdev_push_mt_compat(struct evdev_dev *evdev) 2652b3f6d66SOleksandr Tymoshenko { 2662b3f6d66SOleksandr Tymoshenko 267bfbd1bb7SOleksandr Tymoshenko if (evdev->ev_lock_type == EV_LOCK_INTERNAL) 2682b3f6d66SOleksandr Tymoshenko EVDEV_LOCK(evdev); 269bfbd1bb7SOleksandr Tymoshenko else 270bfbd1bb7SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 2712b3f6d66SOleksandr Tymoshenko evdev_send_mt_compat(evdev); 272bfbd1bb7SOleksandr Tymoshenko if (evdev->ev_lock_type == EV_LOCK_INTERNAL) 2732b3f6d66SOleksandr Tymoshenko EVDEV_UNLOCK(evdev); 2742b3f6d66SOleksandr Tymoshenko } 275*c736a757SOleksandr Tymoshenko 276*c736a757SOleksandr Tymoshenko void 277*c736a757SOleksandr Tymoshenko evdev_send_mt_autorel(struct evdev_dev *evdev) 278*c736a757SOleksandr Tymoshenko { 279*c736a757SOleksandr Tymoshenko int32_t slot; 280*c736a757SOleksandr Tymoshenko 281*c736a757SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 282*c736a757SOleksandr Tymoshenko 283*c736a757SOleksandr Tymoshenko for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) { 284*c736a757SOleksandr Tymoshenko if (evdev->ev_mt->ev_mt_slots[slot].ev_report != 285*c736a757SOleksandr Tymoshenko evdev->ev_report_count && 286*c736a757SOleksandr Tymoshenko evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID) != -1){ 287*c736a757SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot); 288*c736a757SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID, 289*c736a757SOleksandr Tymoshenko -1); 290*c736a757SOleksandr Tymoshenko } 291*c736a757SOleksandr Tymoshenko } 292*c736a757SOleksandr Tymoshenko } 293