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 452dc7188eSVladimir Kondratyev typedef u_int slotset_t; 462dc7188eSVladimir Kondratyev 472dc7188eSVladimir Kondratyev _Static_assert(MAX_MT_SLOTS < sizeof(slotset_t) * 8, "MAX_MT_SLOTS too big"); 482dc7188eSVladimir Kondratyev 492dc7188eSVladimir Kondratyev #define FOREACHBIT(v, i) \ 502dc7188eSVladimir Kondratyev for ((i) = ffs(v) - 1; (i) != -1; (i) = ffs((v) & (~1 << (i))) - 1) 512dc7188eSVladimir Kondratyev 52*127e54deSVladimir Kondratyev struct { 53*127e54deSVladimir Kondratyev uint16_t mt; 54*127e54deSVladimir Kondratyev uint16_t st; 55*127e54deSVladimir Kondratyev int32_t max; 56*127e54deSVladimir Kondratyev } static evdev_mtstmap[] = { 57*127e54deSVladimir Kondratyev { ABS_MT_POSITION_X, ABS_X, 0 }, 58*127e54deSVladimir Kondratyev { ABS_MT_POSITION_Y, ABS_Y, 0 }, 59*127e54deSVladimir Kondratyev { ABS_MT_PRESSURE, ABS_PRESSURE, 255 }, 60*127e54deSVladimir Kondratyev { ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH, 15 }, 612b3f6d66SOleksandr Tymoshenko }; 622b3f6d66SOleksandr Tymoshenko 632b3f6d66SOleksandr Tymoshenko struct evdev_mt_slot { 6498a7606bSVladimir Kondratyev int32_t val[MT_CNT]; 652b3f6d66SOleksandr Tymoshenko }; 662b3f6d66SOleksandr Tymoshenko 672b3f6d66SOleksandr Tymoshenko struct evdev_mt { 6898a7606bSVladimir Kondratyev int last_reported_slot; 69*127e54deSVladimir Kondratyev u_int mtst_events; 702dc7188eSVladimir Kondratyev /* the set of slots with active touches */ 712dc7188eSVladimir Kondratyev slotset_t touches; 722dc7188eSVladimir Kondratyev /* the set of slots with unsynchronized state */ 732dc7188eSVladimir Kondratyev slotset_t frame; 7498a7606bSVladimir Kondratyev struct evdev_mt_slot slots[]; 752b3f6d66SOleksandr Tymoshenko }; 762b3f6d66SOleksandr Tymoshenko 7798a7606bSVladimir Kondratyev static void evdev_mt_send_st_compat(struct evdev_dev *); 7898a7606bSVladimir Kondratyev static void evdev_mt_send_autorel(struct evdev_dev *); 7998a7606bSVladimir Kondratyev 802dc7188eSVladimir Kondratyev static inline int 812dc7188eSVladimir Kondratyev ffc_slot(struct evdev_dev *evdev, slotset_t slots) 822dc7188eSVladimir Kondratyev { 832dc7188eSVladimir Kondratyev return (ffs(~slots & (2U << MAXIMAL_MT_SLOT(evdev)) - 1) - 1); 842dc7188eSVladimir Kondratyev } 852dc7188eSVladimir Kondratyev 862b3f6d66SOleksandr Tymoshenko void 872b3f6d66SOleksandr Tymoshenko evdev_mt_init(struct evdev_dev *evdev) 882b3f6d66SOleksandr Tymoshenko { 8998a7606bSVladimir Kondratyev int slot, slots; 902b3f6d66SOleksandr Tymoshenko 912b3f6d66SOleksandr Tymoshenko slots = MAXIMAL_MT_SLOT(evdev) + 1; 922b3f6d66SOleksandr Tymoshenko 9398a7606bSVladimir Kondratyev evdev->ev_mt = malloc(offsetof(struct evdev_mt, slots) + 942b3f6d66SOleksandr Tymoshenko sizeof(struct evdev_mt_slot) * slots, M_EVDEV, M_WAITOK | M_ZERO); 952b3f6d66SOleksandr Tymoshenko 962b3f6d66SOleksandr Tymoshenko /* Initialize multitouch protocol type B states */ 972dc7188eSVladimir Kondratyev for (slot = 0; slot < slots; slot++) 982dc7188eSVladimir Kondratyev evdev->ev_mt->slots[slot].val[ABS_MT_INDEX(ABS_MT_TRACKING_ID)] 992dc7188eSVladimir Kondratyev = -1; 1002b3f6d66SOleksandr Tymoshenko 1012b3f6d66SOleksandr Tymoshenko if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) 1022b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(evdev); 1032b3f6d66SOleksandr Tymoshenko } 1042b3f6d66SOleksandr Tymoshenko 1052b3f6d66SOleksandr Tymoshenko void 1062b3f6d66SOleksandr Tymoshenko evdev_mt_free(struct evdev_dev *evdev) 1072b3f6d66SOleksandr Tymoshenko { 1082b3f6d66SOleksandr Tymoshenko free(evdev->ev_mt, M_EVDEV); 1092b3f6d66SOleksandr Tymoshenko } 1102b3f6d66SOleksandr Tymoshenko 11198a7606bSVladimir Kondratyev void 11298a7606bSVladimir Kondratyev evdev_mt_sync_frame(struct evdev_dev *evdev) 1132b3f6d66SOleksandr Tymoshenko { 11498a7606bSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL)) 11598a7606bSVladimir Kondratyev evdev_mt_send_autorel(evdev); 11698a7606bSVladimir Kondratyev if (evdev->ev_report_opened && 11798a7606bSVladimir Kondratyev bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) 11898a7606bSVladimir Kondratyev evdev_mt_send_st_compat(evdev); 1192dc7188eSVladimir Kondratyev evdev->ev_mt->frame = 0; 12098a7606bSVladimir Kondratyev } 1212b3f6d66SOleksandr Tymoshenko 12298a7606bSVladimir Kondratyev int 12398a7606bSVladimir Kondratyev evdev_mt_get_last_slot(struct evdev_dev *evdev) 12498a7606bSVladimir Kondratyev { 12598a7606bSVladimir Kondratyev return (evdev->ev_mt->last_reported_slot); 1262b3f6d66SOleksandr Tymoshenko } 1272b3f6d66SOleksandr Tymoshenko 1282b3f6d66SOleksandr Tymoshenko void 12998a7606bSVladimir Kondratyev evdev_mt_set_last_slot(struct evdev_dev *evdev, int slot) 1302b3f6d66SOleksandr Tymoshenko { 13198a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 1322b3f6d66SOleksandr Tymoshenko 13398a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 1342b3f6d66SOleksandr Tymoshenko 1352dc7188eSVladimir Kondratyev mt->frame |= 1U << slot; 13698a7606bSVladimir Kondratyev mt->last_reported_slot = slot; 1372b3f6d66SOleksandr Tymoshenko } 1382b3f6d66SOleksandr Tymoshenko 1392b3f6d66SOleksandr Tymoshenko int32_t 14098a7606bSVladimir Kondratyev evdev_mt_get_value(struct evdev_dev *evdev, int slot, int16_t code) 14198a7606bSVladimir Kondratyev { 14298a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 14398a7606bSVladimir Kondratyev 14498a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 14598a7606bSVladimir Kondratyev 14698a7606bSVladimir Kondratyev return (mt->slots[slot].val[ABS_MT_INDEX(code)]); 14798a7606bSVladimir Kondratyev } 14898a7606bSVladimir Kondratyev 14998a7606bSVladimir Kondratyev void 15098a7606bSVladimir Kondratyev evdev_mt_set_value(struct evdev_dev *evdev, int slot, int16_t code, 15198a7606bSVladimir Kondratyev int32_t value) 15298a7606bSVladimir Kondratyev { 15398a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 15498a7606bSVladimir Kondratyev 15598a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 15698a7606bSVladimir Kondratyev 1572dc7188eSVladimir Kondratyev if (code == ABS_MT_TRACKING_ID) { 1582dc7188eSVladimir Kondratyev if (value != -1) 1592dc7188eSVladimir Kondratyev mt->touches |= 1U << slot; 1602dc7188eSVladimir Kondratyev else 1612dc7188eSVladimir Kondratyev mt->touches &= ~(1U << slot); 1622dc7188eSVladimir Kondratyev } 16398a7606bSVladimir Kondratyev mt->slots[slot].val[ABS_MT_INDEX(code)] = value; 16498a7606bSVladimir Kondratyev } 16598a7606bSVladimir Kondratyev 16698a7606bSVladimir Kondratyev int 1672b3f6d66SOleksandr Tymoshenko evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id) 1682b3f6d66SOleksandr Tymoshenko { 16998a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 1702dc7188eSVladimir Kondratyev int slot; 1712b3f6d66SOleksandr Tymoshenko 1722dc7188eSVladimir Kondratyev FOREACHBIT(mt->touches, slot) 1732dc7188eSVladimir Kondratyev if (evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID) == 1742dc7188eSVladimir Kondratyev tracking_id) 1752b3f6d66SOleksandr Tymoshenko return (slot); 1762b3f6d66SOleksandr Tymoshenko /* 1772dc7188eSVladimir Kondratyev * Do not allow allocation of new slot in a place of just 1782dc7188eSVladimir Kondratyev * released one within the same report. 1792b3f6d66SOleksandr Tymoshenko */ 1802dc7188eSVladimir Kondratyev return (ffc_slot(evdev, mt->touches | mt->frame)); 1812b3f6d66SOleksandr Tymoshenko } 1822b3f6d66SOleksandr Tymoshenko 183*127e54deSVladimir Kondratyev static inline int32_t 184*127e54deSVladimir Kondratyev evdev_mt_normalize(int32_t value, int32_t mtmin, int32_t mtmax, int32_t stmax) 185*127e54deSVladimir Kondratyev { 186*127e54deSVladimir Kondratyev if (stmax != 0 && mtmax != mtmin) { 187*127e54deSVladimir Kondratyev value = (value - mtmin) * stmax / (mtmax - mtmin); 188*127e54deSVladimir Kondratyev value = MAX(MIN(value, stmax), 0); 189*127e54deSVladimir Kondratyev } 190*127e54deSVladimir Kondratyev return (value); 191*127e54deSVladimir Kondratyev } 192*127e54deSVladimir Kondratyev 1932b3f6d66SOleksandr Tymoshenko void 1942b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(struct evdev_dev *evdev) 1952b3f6d66SOleksandr Tymoshenko { 196*127e54deSVladimir Kondratyev struct input_absinfo *ai; 19798a7606bSVladimir Kondratyev int i; 1982b3f6d66SOleksandr Tymoshenko 1992b3f6d66SOleksandr Tymoshenko if (evdev->ev_absinfo == NULL) 2002b3f6d66SOleksandr Tymoshenko return; 2012b3f6d66SOleksandr Tymoshenko 2022b3f6d66SOleksandr Tymoshenko evdev_support_event(evdev, EV_KEY); 2032b3f6d66SOleksandr Tymoshenko evdev_support_key(evdev, BTN_TOUCH); 2042b3f6d66SOleksandr Tymoshenko 2052b3f6d66SOleksandr Tymoshenko /* Touchscreens should not advertise tap tool capabilities */ 2062b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 2072b3f6d66SOleksandr Tymoshenko evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1); 2082b3f6d66SOleksandr Tymoshenko 2092b3f6d66SOleksandr Tymoshenko /* Echo 0-th MT-slot as ST-slot */ 210*127e54deSVladimir Kondratyev for (i = 0; i < nitems(evdev_mtstmap); i++) { 211*127e54deSVladimir Kondratyev if (!bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].mt) || 212*127e54deSVladimir Kondratyev bit_test(evdev->ev_abs_flags, evdev_mtstmap[i].st)) 213*127e54deSVladimir Kondratyev continue; 214*127e54deSVladimir Kondratyev ai = evdev->ev_absinfo + evdev_mtstmap[i].mt; 215*127e54deSVladimir Kondratyev evdev->ev_mt->mtst_events |= 1U << i; 216*127e54deSVladimir Kondratyev if (evdev_mtstmap[i].max != 0) 217*127e54deSVladimir Kondratyev evdev_support_abs(evdev, evdev_mtstmap[i].st, 218314913edSVladimir Kondratyev 0, 219*127e54deSVladimir Kondratyev evdev_mtstmap[i].max, 220*127e54deSVladimir Kondratyev 0, 221*127e54deSVladimir Kondratyev evdev_mt_normalize( 222*127e54deSVladimir Kondratyev ai->flat, 0, ai->maximum, evdev_mtstmap[i].max), 223*127e54deSVladimir Kondratyev 0); 224*127e54deSVladimir Kondratyev else 225*127e54deSVladimir Kondratyev evdev_support_abs(evdev, evdev_mtstmap[i].st, 226*127e54deSVladimir Kondratyev ai->minimum, 227*127e54deSVladimir Kondratyev ai->maximum, 228*127e54deSVladimir Kondratyev 0, 229*127e54deSVladimir Kondratyev ai->flat, 230*127e54deSVladimir Kondratyev ai->resolution); 231*127e54deSVladimir Kondratyev } 2322b3f6d66SOleksandr Tymoshenko } 2332b3f6d66SOleksandr Tymoshenko 2342b3f6d66SOleksandr Tymoshenko static void 23598a7606bSVladimir Kondratyev evdev_mt_send_st_compat(struct evdev_dev *evdev) 2362b3f6d66SOleksandr Tymoshenko { 2372dc7188eSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 238fbe17f90SVladimir Kondratyev int nfingers, i, st_slot; 2392b3f6d66SOleksandr Tymoshenko 2402b3f6d66SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 2412b3f6d66SOleksandr Tymoshenko 2422dc7188eSVladimir Kondratyev nfingers = bitcount(mt->touches); 2432b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0); 2442b3f6d66SOleksandr Tymoshenko 245fbe17f90SVladimir Kondratyev /* Send first active MT-slot state as single touch report */ 246fbe17f90SVladimir Kondratyev st_slot = ffs(mt->touches) - 1; 247fbe17f90SVladimir Kondratyev if (st_slot != -1) 248*127e54deSVladimir Kondratyev FOREACHBIT(mt->mtst_events, i) 249*127e54deSVladimir Kondratyev evdev_send_event(evdev, EV_ABS, evdev_mtstmap[i].st, 250*127e54deSVladimir Kondratyev evdev_mt_normalize(evdev_mt_get_value(evdev, 251*127e54deSVladimir Kondratyev st_slot, evdev_mtstmap[i].mt), 252*127e54deSVladimir Kondratyev evdev->ev_absinfo[evdev_mtstmap[i].mt].minimum, 253*127e54deSVladimir Kondratyev evdev->ev_absinfo[evdev_mtstmap[i].mt].maximum, 254*127e54deSVladimir Kondratyev evdev_mtstmap[i].max)); 2552b3f6d66SOleksandr Tymoshenko 2562b3f6d66SOleksandr Tymoshenko /* Touchscreens should not report tool taps */ 2572b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 2582b3f6d66SOleksandr Tymoshenko evdev_send_nfingers(evdev, nfingers); 2592b3f6d66SOleksandr Tymoshenko 2602b3f6d66SOleksandr Tymoshenko if (nfingers == 0) 2612b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0); 2622b3f6d66SOleksandr Tymoshenko } 2632b3f6d66SOleksandr Tymoshenko 2642b3f6d66SOleksandr Tymoshenko void 2652b3f6d66SOleksandr Tymoshenko evdev_push_mt_compat(struct evdev_dev *evdev) 2662b3f6d66SOleksandr Tymoshenko { 2672b3f6d66SOleksandr Tymoshenko 2684c0a4665SVladimir Kondratyev EVDEV_ENTER(evdev); 26998a7606bSVladimir Kondratyev evdev_mt_send_st_compat(evdev); 2704c0a4665SVladimir Kondratyev EVDEV_EXIT(evdev); 2712b3f6d66SOleksandr Tymoshenko } 272c736a757SOleksandr Tymoshenko 27398a7606bSVladimir Kondratyev static void 27498a7606bSVladimir Kondratyev evdev_mt_send_autorel(struct evdev_dev *evdev) 275c736a757SOleksandr Tymoshenko { 27698a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 27798a7606bSVladimir Kondratyev int slot; 278c736a757SOleksandr Tymoshenko 279c736a757SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 280c736a757SOleksandr Tymoshenko 2812dc7188eSVladimir Kondratyev FOREACHBIT(mt->touches & ~mt->frame, slot) { 282c736a757SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot); 2832dc7188eSVladimir Kondratyev evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID, -1); 284c736a757SOleksandr Tymoshenko } 285c736a757SOleksandr Tymoshenko } 28698a7606bSVladimir Kondratyev 28798a7606bSVladimir Kondratyev void 28898a7606bSVladimir Kondratyev evdev_mt_push_autorel(struct evdev_dev *evdev) 28998a7606bSVladimir Kondratyev { 29098a7606bSVladimir Kondratyev EVDEV_ENTER(evdev); 29198a7606bSVladimir Kondratyev evdev_mt_send_autorel(evdev); 29298a7606bSVladimir Kondratyev EVDEV_EXIT(evdev); 29398a7606bSVladimir Kondratyev } 294