12b3f6d66SOleksandr Tymoshenko /*- 2e6502802SVladimir Kondratyev * Copyright (c) 2016 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 */ 282b3f6d66SOleksandr Tymoshenko 292b3f6d66SOleksandr Tymoshenko #include <sys/param.h> 302b3f6d66SOleksandr Tymoshenko #include <sys/lock.h> 31ea2e26b1SVladimir Kondratyev #include <sys/malloc.h> 322b3f6d66SOleksandr Tymoshenko #include <sys/mutex.h> 332b3f6d66SOleksandr Tymoshenko #include <sys/systm.h> 342b3f6d66SOleksandr Tymoshenko 352b3f6d66SOleksandr Tymoshenko #include <dev/evdev/evdev.h> 362b3f6d66SOleksandr Tymoshenko #include <dev/evdev/evdev_private.h> 37ea2e26b1SVladimir Kondratyev #include <dev/evdev/input.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_mtstmap[][2] = { 462b3f6d66SOleksandr Tymoshenko { ABS_MT_POSITION_X, ABS_X }, 472b3f6d66SOleksandr Tymoshenko { ABS_MT_POSITION_Y, ABS_Y }, 482b3f6d66SOleksandr Tymoshenko { ABS_MT_PRESSURE, ABS_PRESSURE }, 492b3f6d66SOleksandr Tymoshenko { ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH }, 502b3f6d66SOleksandr Tymoshenko }; 512b3f6d66SOleksandr Tymoshenko 522b3f6d66SOleksandr Tymoshenko struct evdev_mt_slot { 532b3f6d66SOleksandr Tymoshenko uint64_t ev_report; 54*98a7606bSVladimir Kondratyev int32_t val[MT_CNT]; 552b3f6d66SOleksandr Tymoshenko }; 562b3f6d66SOleksandr Tymoshenko 572b3f6d66SOleksandr Tymoshenko struct evdev_mt { 58*98a7606bSVladimir Kondratyev int last_reported_slot; 59*98a7606bSVladimir Kondratyev struct evdev_mt_slot slots[]; 602b3f6d66SOleksandr Tymoshenko }; 612b3f6d66SOleksandr Tymoshenko 62*98a7606bSVladimir Kondratyev static void evdev_mt_send_st_compat(struct evdev_dev *); 63*98a7606bSVladimir Kondratyev static void evdev_mt_send_autorel(struct evdev_dev *); 64*98a7606bSVladimir Kondratyev 652b3f6d66SOleksandr Tymoshenko void 662b3f6d66SOleksandr Tymoshenko evdev_mt_init(struct evdev_dev *evdev) 672b3f6d66SOleksandr Tymoshenko { 68*98a7606bSVladimir Kondratyev int slot, slots; 692b3f6d66SOleksandr Tymoshenko 702b3f6d66SOleksandr Tymoshenko slots = MAXIMAL_MT_SLOT(evdev) + 1; 712b3f6d66SOleksandr Tymoshenko 72*98a7606bSVladimir Kondratyev evdev->ev_mt = malloc(offsetof(struct evdev_mt, slots) + 732b3f6d66SOleksandr Tymoshenko sizeof(struct evdev_mt_slot) * slots, M_EVDEV, M_WAITOK | M_ZERO); 742b3f6d66SOleksandr Tymoshenko 752b3f6d66SOleksandr Tymoshenko /* Initialize multitouch protocol type B states */ 762b3f6d66SOleksandr Tymoshenko for (slot = 0; slot < slots; slot++) { 772b3f6d66SOleksandr Tymoshenko /* 782b3f6d66SOleksandr Tymoshenko * .ev_report should not be initialized to initial value of 792b3f6d66SOleksandr Tymoshenko * report counter (0) as it brokes free slot detection in 802b3f6d66SOleksandr Tymoshenko * evdev_get_mt_slot_by_tracking_id. So initialize it to -1 812b3f6d66SOleksandr Tymoshenko */ 82*98a7606bSVladimir Kondratyev evdev->ev_mt->slots[slot] = (struct evdev_mt_slot) { 832b3f6d66SOleksandr Tymoshenko .ev_report = 0xFFFFFFFFFFFFFFFFULL, 84*98a7606bSVladimir Kondratyev .val[ABS_MT_INDEX(ABS_MT_TRACKING_ID)] = -1, 852b3f6d66SOleksandr Tymoshenko }; 862b3f6d66SOleksandr Tymoshenko } 872b3f6d66SOleksandr Tymoshenko 882b3f6d66SOleksandr Tymoshenko if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) 892b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(evdev); 902b3f6d66SOleksandr Tymoshenko } 912b3f6d66SOleksandr Tymoshenko 922b3f6d66SOleksandr Tymoshenko void 932b3f6d66SOleksandr Tymoshenko evdev_mt_free(struct evdev_dev *evdev) 942b3f6d66SOleksandr Tymoshenko { 952b3f6d66SOleksandr Tymoshenko free(evdev->ev_mt, M_EVDEV); 962b3f6d66SOleksandr Tymoshenko } 972b3f6d66SOleksandr Tymoshenko 98*98a7606bSVladimir Kondratyev void 99*98a7606bSVladimir Kondratyev evdev_mt_sync_frame(struct evdev_dev *evdev) 1002b3f6d66SOleksandr Tymoshenko { 101*98a7606bSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL)) 102*98a7606bSVladimir Kondratyev evdev_mt_send_autorel(evdev); 103*98a7606bSVladimir Kondratyev if (evdev->ev_report_opened && 104*98a7606bSVladimir Kondratyev bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) 105*98a7606bSVladimir Kondratyev evdev_mt_send_st_compat(evdev); 106*98a7606bSVladimir Kondratyev } 1072b3f6d66SOleksandr Tymoshenko 108*98a7606bSVladimir Kondratyev int 109*98a7606bSVladimir Kondratyev evdev_mt_get_last_slot(struct evdev_dev *evdev) 110*98a7606bSVladimir Kondratyev { 111*98a7606bSVladimir Kondratyev return (evdev->ev_mt->last_reported_slot); 1122b3f6d66SOleksandr Tymoshenko } 1132b3f6d66SOleksandr Tymoshenko 1142b3f6d66SOleksandr Tymoshenko void 115*98a7606bSVladimir Kondratyev evdev_mt_set_last_slot(struct evdev_dev *evdev, int slot) 1162b3f6d66SOleksandr Tymoshenko { 117*98a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 1182b3f6d66SOleksandr Tymoshenko 119*98a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 1202b3f6d66SOleksandr Tymoshenko 121*98a7606bSVladimir Kondratyev mt->slots[slot].ev_report = evdev->ev_report_count; 122*98a7606bSVladimir Kondratyev mt->last_reported_slot = slot; 1232b3f6d66SOleksandr Tymoshenko } 1242b3f6d66SOleksandr Tymoshenko 1252b3f6d66SOleksandr Tymoshenko int32_t 126*98a7606bSVladimir Kondratyev evdev_mt_get_value(struct evdev_dev *evdev, int slot, int16_t code) 127*98a7606bSVladimir Kondratyev { 128*98a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 129*98a7606bSVladimir Kondratyev 130*98a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 131*98a7606bSVladimir Kondratyev 132*98a7606bSVladimir Kondratyev return (mt->slots[slot].val[ABS_MT_INDEX(code)]); 133*98a7606bSVladimir Kondratyev } 134*98a7606bSVladimir Kondratyev 135*98a7606bSVladimir Kondratyev void 136*98a7606bSVladimir Kondratyev evdev_mt_set_value(struct evdev_dev *evdev, int slot, int16_t code, 137*98a7606bSVladimir Kondratyev int32_t value) 138*98a7606bSVladimir Kondratyev { 139*98a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 140*98a7606bSVladimir Kondratyev 141*98a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 142*98a7606bSVladimir Kondratyev 143*98a7606bSVladimir Kondratyev mt->slots[slot].val[ABS_MT_INDEX(code)] = value; 144*98a7606bSVladimir Kondratyev } 145*98a7606bSVladimir Kondratyev 146*98a7606bSVladimir Kondratyev int 1472b3f6d66SOleksandr Tymoshenko evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id) 1482b3f6d66SOleksandr Tymoshenko { 149*98a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 150*98a7606bSVladimir Kondratyev int32_t tr_id; 151*98a7606bSVladimir Kondratyev int slot, free_slot = -1; 1522b3f6d66SOleksandr Tymoshenko 1532b3f6d66SOleksandr Tymoshenko for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) { 154*98a7606bSVladimir Kondratyev tr_id = evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID); 1552b3f6d66SOleksandr Tymoshenko if (tr_id == tracking_id) 1562b3f6d66SOleksandr Tymoshenko return (slot); 1572b3f6d66SOleksandr Tymoshenko /* 1582b3f6d66SOleksandr Tymoshenko * Its possible that slot will be reassigned in a place of just 1592b3f6d66SOleksandr Tymoshenko * released one within the same report. To avoid this compare 1602b3f6d66SOleksandr Tymoshenko * report counter with slot`s report number updated with each 1612b3f6d66SOleksandr Tymoshenko * ABS_MT_TRACKING_ID change. 1622b3f6d66SOleksandr Tymoshenko */ 1632b3f6d66SOleksandr Tymoshenko if (free_slot == -1 && tr_id == -1 && 164*98a7606bSVladimir Kondratyev mt->slots[slot].ev_report != evdev->ev_report_count) 1652b3f6d66SOleksandr Tymoshenko free_slot = slot; 1662b3f6d66SOleksandr Tymoshenko } 1672b3f6d66SOleksandr Tymoshenko 1682b3f6d66SOleksandr Tymoshenko return (free_slot); 1692b3f6d66SOleksandr Tymoshenko } 1702b3f6d66SOleksandr Tymoshenko 1712b3f6d66SOleksandr Tymoshenko void 1722b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(struct evdev_dev *evdev) 1732b3f6d66SOleksandr Tymoshenko { 174*98a7606bSVladimir Kondratyev int i; 1752b3f6d66SOleksandr Tymoshenko 1762b3f6d66SOleksandr Tymoshenko if (evdev->ev_absinfo == NULL) 1772b3f6d66SOleksandr Tymoshenko return; 1782b3f6d66SOleksandr Tymoshenko 1792b3f6d66SOleksandr Tymoshenko evdev_support_event(evdev, EV_KEY); 1802b3f6d66SOleksandr Tymoshenko evdev_support_key(evdev, BTN_TOUCH); 1812b3f6d66SOleksandr Tymoshenko 1822b3f6d66SOleksandr Tymoshenko /* Touchscreens should not advertise tap tool capabilities */ 1832b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 1842b3f6d66SOleksandr Tymoshenko evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1); 1852b3f6d66SOleksandr Tymoshenko 1862b3f6d66SOleksandr Tymoshenko /* Echo 0-th MT-slot as ST-slot */ 1872b3f6d66SOleksandr Tymoshenko for (i = 0; i < nitems(evdev_mtstmap); i++) 1882b3f6d66SOleksandr Tymoshenko if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][0])) 1892b3f6d66SOleksandr Tymoshenko evdev_support_abs(evdev, evdev_mtstmap[i][1], 1902b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].minimum, 1912b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].maximum, 1922b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].fuzz, 1932b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].flat, 1942b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].resolution); 1952b3f6d66SOleksandr Tymoshenko } 1962b3f6d66SOleksandr Tymoshenko 1972b3f6d66SOleksandr Tymoshenko static int32_t 1982b3f6d66SOleksandr Tymoshenko evdev_count_fingers(struct evdev_dev *evdev) 1992b3f6d66SOleksandr Tymoshenko { 200*98a7606bSVladimir Kondratyev int nfingers = 0, i; 2012b3f6d66SOleksandr Tymoshenko 2022b3f6d66SOleksandr Tymoshenko for (i = 0; i <= MAXIMAL_MT_SLOT(evdev); i++) 203*98a7606bSVladimir Kondratyev if (evdev_mt_get_value(evdev, i, ABS_MT_TRACKING_ID) != -1) 2042b3f6d66SOleksandr Tymoshenko nfingers++; 2052b3f6d66SOleksandr Tymoshenko 2062b3f6d66SOleksandr Tymoshenko return (nfingers); 2072b3f6d66SOleksandr Tymoshenko } 2082b3f6d66SOleksandr Tymoshenko 2092b3f6d66SOleksandr Tymoshenko static void 210*98a7606bSVladimir Kondratyev evdev_mt_send_st_compat(struct evdev_dev *evdev) 2112b3f6d66SOleksandr Tymoshenko { 212*98a7606bSVladimir Kondratyev int nfingers, i; 2132b3f6d66SOleksandr Tymoshenko 2142b3f6d66SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 2152b3f6d66SOleksandr Tymoshenko 2162b3f6d66SOleksandr Tymoshenko nfingers = evdev_count_fingers(evdev); 2172b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0); 2182b3f6d66SOleksandr Tymoshenko 219*98a7606bSVladimir Kondratyev if (evdev_mt_get_value(evdev, 0, ABS_MT_TRACKING_ID) != -1) 2202b3f6d66SOleksandr Tymoshenko /* Echo 0-th MT-slot as ST-slot */ 2212b3f6d66SOleksandr Tymoshenko for (i = 0; i < nitems(evdev_mtstmap); i++) 2222b3f6d66SOleksandr Tymoshenko if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][1])) 2232b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, 2242b3f6d66SOleksandr Tymoshenko evdev_mtstmap[i][1], 225*98a7606bSVladimir Kondratyev evdev_mt_get_value(evdev, 0, 2262b3f6d66SOleksandr Tymoshenko evdev_mtstmap[i][0])); 2272b3f6d66SOleksandr Tymoshenko 2282b3f6d66SOleksandr Tymoshenko /* Touchscreens should not report tool taps */ 2292b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 2302b3f6d66SOleksandr Tymoshenko evdev_send_nfingers(evdev, nfingers); 2312b3f6d66SOleksandr Tymoshenko 2322b3f6d66SOleksandr Tymoshenko if (nfingers == 0) 2332b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0); 2342b3f6d66SOleksandr Tymoshenko } 2352b3f6d66SOleksandr Tymoshenko 2362b3f6d66SOleksandr Tymoshenko void 2372b3f6d66SOleksandr Tymoshenko evdev_push_mt_compat(struct evdev_dev *evdev) 2382b3f6d66SOleksandr Tymoshenko { 2392b3f6d66SOleksandr Tymoshenko 2404c0a4665SVladimir Kondratyev EVDEV_ENTER(evdev); 241*98a7606bSVladimir Kondratyev evdev_mt_send_st_compat(evdev); 2424c0a4665SVladimir Kondratyev EVDEV_EXIT(evdev); 2432b3f6d66SOleksandr Tymoshenko } 244c736a757SOleksandr Tymoshenko 245*98a7606bSVladimir Kondratyev static void 246*98a7606bSVladimir Kondratyev evdev_mt_send_autorel(struct evdev_dev *evdev) 247c736a757SOleksandr Tymoshenko { 248*98a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 249*98a7606bSVladimir Kondratyev int slot; 250c736a757SOleksandr Tymoshenko 251c736a757SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 252c736a757SOleksandr Tymoshenko 253c736a757SOleksandr Tymoshenko for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) { 254*98a7606bSVladimir Kondratyev if (mt->slots[slot].ev_report != evdev->ev_report_count && 255*98a7606bSVladimir Kondratyev evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID) != -1){ 256c736a757SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot); 257c736a757SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID, 258c736a757SOleksandr Tymoshenko -1); 259c736a757SOleksandr Tymoshenko } 260c736a757SOleksandr Tymoshenko } 261c736a757SOleksandr Tymoshenko } 262*98a7606bSVladimir Kondratyev 263*98a7606bSVladimir Kondratyev void 264*98a7606bSVladimir Kondratyev evdev_mt_push_autorel(struct evdev_dev *evdev) 265*98a7606bSVladimir Kondratyev { 266*98a7606bSVladimir Kondratyev EVDEV_ENTER(evdev); 267*98a7606bSVladimir Kondratyev evdev_mt_send_autorel(evdev); 268*98a7606bSVladimir Kondratyev EVDEV_EXIT(evdev); 269*98a7606bSVladimir Kondratyev } 270