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 522b3f6d66SOleksandr Tymoshenko static uint16_t evdev_mtstmap[][2] = { 532b3f6d66SOleksandr Tymoshenko { ABS_MT_POSITION_X, ABS_X }, 542b3f6d66SOleksandr Tymoshenko { ABS_MT_POSITION_Y, ABS_Y }, 552b3f6d66SOleksandr Tymoshenko { ABS_MT_PRESSURE, ABS_PRESSURE }, 562b3f6d66SOleksandr Tymoshenko { ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH }, 572b3f6d66SOleksandr Tymoshenko }; 582b3f6d66SOleksandr Tymoshenko 592b3f6d66SOleksandr Tymoshenko struct evdev_mt_slot { 6098a7606bSVladimir Kondratyev int32_t val[MT_CNT]; 612b3f6d66SOleksandr Tymoshenko }; 622b3f6d66SOleksandr Tymoshenko 632b3f6d66SOleksandr Tymoshenko struct evdev_mt { 6498a7606bSVladimir Kondratyev int last_reported_slot; 652dc7188eSVladimir Kondratyev /* the set of slots with active touches */ 662dc7188eSVladimir Kondratyev slotset_t touches; 672dc7188eSVladimir Kondratyev /* the set of slots with unsynchronized state */ 682dc7188eSVladimir Kondratyev slotset_t frame; 6998a7606bSVladimir Kondratyev struct evdev_mt_slot slots[]; 702b3f6d66SOleksandr Tymoshenko }; 712b3f6d66SOleksandr Tymoshenko 7298a7606bSVladimir Kondratyev static void evdev_mt_send_st_compat(struct evdev_dev *); 7398a7606bSVladimir Kondratyev static void evdev_mt_send_autorel(struct evdev_dev *); 7498a7606bSVladimir Kondratyev 752dc7188eSVladimir Kondratyev static inline int 762dc7188eSVladimir Kondratyev ffc_slot(struct evdev_dev *evdev, slotset_t slots) 772dc7188eSVladimir Kondratyev { 782dc7188eSVladimir Kondratyev return (ffs(~slots & (2U << MAXIMAL_MT_SLOT(evdev)) - 1) - 1); 792dc7188eSVladimir Kondratyev } 802dc7188eSVladimir Kondratyev 812b3f6d66SOleksandr Tymoshenko void 822b3f6d66SOleksandr Tymoshenko evdev_mt_init(struct evdev_dev *evdev) 832b3f6d66SOleksandr Tymoshenko { 8498a7606bSVladimir Kondratyev int slot, slots; 852b3f6d66SOleksandr Tymoshenko 862b3f6d66SOleksandr Tymoshenko slots = MAXIMAL_MT_SLOT(evdev) + 1; 872b3f6d66SOleksandr Tymoshenko 8898a7606bSVladimir Kondratyev evdev->ev_mt = malloc(offsetof(struct evdev_mt, slots) + 892b3f6d66SOleksandr Tymoshenko sizeof(struct evdev_mt_slot) * slots, M_EVDEV, M_WAITOK | M_ZERO); 902b3f6d66SOleksandr Tymoshenko 912b3f6d66SOleksandr Tymoshenko /* Initialize multitouch protocol type B states */ 922dc7188eSVladimir Kondratyev for (slot = 0; slot < slots; slot++) 932dc7188eSVladimir Kondratyev evdev->ev_mt->slots[slot].val[ABS_MT_INDEX(ABS_MT_TRACKING_ID)] 942dc7188eSVladimir Kondratyev = -1; 952b3f6d66SOleksandr Tymoshenko 962b3f6d66SOleksandr Tymoshenko if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) 972b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(evdev); 982b3f6d66SOleksandr Tymoshenko } 992b3f6d66SOleksandr Tymoshenko 1002b3f6d66SOleksandr Tymoshenko void 1012b3f6d66SOleksandr Tymoshenko evdev_mt_free(struct evdev_dev *evdev) 1022b3f6d66SOleksandr Tymoshenko { 1032b3f6d66SOleksandr Tymoshenko free(evdev->ev_mt, M_EVDEV); 1042b3f6d66SOleksandr Tymoshenko } 1052b3f6d66SOleksandr Tymoshenko 10698a7606bSVladimir Kondratyev void 10798a7606bSVladimir Kondratyev evdev_mt_sync_frame(struct evdev_dev *evdev) 1082b3f6d66SOleksandr Tymoshenko { 10998a7606bSVladimir Kondratyev if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL)) 11098a7606bSVladimir Kondratyev evdev_mt_send_autorel(evdev); 11198a7606bSVladimir Kondratyev if (evdev->ev_report_opened && 11298a7606bSVladimir Kondratyev bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) 11398a7606bSVladimir Kondratyev evdev_mt_send_st_compat(evdev); 1142dc7188eSVladimir Kondratyev evdev->ev_mt->frame = 0; 11598a7606bSVladimir Kondratyev } 1162b3f6d66SOleksandr Tymoshenko 11798a7606bSVladimir Kondratyev int 11898a7606bSVladimir Kondratyev evdev_mt_get_last_slot(struct evdev_dev *evdev) 11998a7606bSVladimir Kondratyev { 12098a7606bSVladimir Kondratyev return (evdev->ev_mt->last_reported_slot); 1212b3f6d66SOleksandr Tymoshenko } 1222b3f6d66SOleksandr Tymoshenko 1232b3f6d66SOleksandr Tymoshenko void 12498a7606bSVladimir Kondratyev evdev_mt_set_last_slot(struct evdev_dev *evdev, int slot) 1252b3f6d66SOleksandr Tymoshenko { 12698a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 1272b3f6d66SOleksandr Tymoshenko 12898a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 1292b3f6d66SOleksandr Tymoshenko 1302dc7188eSVladimir Kondratyev mt->frame |= 1U << slot; 13198a7606bSVladimir Kondratyev mt->last_reported_slot = slot; 1322b3f6d66SOleksandr Tymoshenko } 1332b3f6d66SOleksandr Tymoshenko 1342b3f6d66SOleksandr Tymoshenko int32_t 13598a7606bSVladimir Kondratyev evdev_mt_get_value(struct evdev_dev *evdev, int slot, int16_t code) 13698a7606bSVladimir Kondratyev { 13798a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 13898a7606bSVladimir Kondratyev 13998a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 14098a7606bSVladimir Kondratyev 14198a7606bSVladimir Kondratyev return (mt->slots[slot].val[ABS_MT_INDEX(code)]); 14298a7606bSVladimir Kondratyev } 14398a7606bSVladimir Kondratyev 14498a7606bSVladimir Kondratyev void 14598a7606bSVladimir Kondratyev evdev_mt_set_value(struct evdev_dev *evdev, int slot, int16_t code, 14698a7606bSVladimir Kondratyev int32_t value) 14798a7606bSVladimir Kondratyev { 14898a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 14998a7606bSVladimir Kondratyev 15098a7606bSVladimir Kondratyev MPASS(slot >= 0 && slot <= MAXIMAL_MT_SLOT(evdev)); 15198a7606bSVladimir Kondratyev 1522dc7188eSVladimir Kondratyev if (code == ABS_MT_TRACKING_ID) { 1532dc7188eSVladimir Kondratyev if (value != -1) 1542dc7188eSVladimir Kondratyev mt->touches |= 1U << slot; 1552dc7188eSVladimir Kondratyev else 1562dc7188eSVladimir Kondratyev mt->touches &= ~(1U << slot); 1572dc7188eSVladimir Kondratyev } 15898a7606bSVladimir Kondratyev mt->slots[slot].val[ABS_MT_INDEX(code)] = value; 15998a7606bSVladimir Kondratyev } 16098a7606bSVladimir Kondratyev 16198a7606bSVladimir Kondratyev int 1622b3f6d66SOleksandr Tymoshenko evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id) 1632b3f6d66SOleksandr Tymoshenko { 16498a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 1652dc7188eSVladimir Kondratyev int slot; 1662b3f6d66SOleksandr Tymoshenko 1672dc7188eSVladimir Kondratyev FOREACHBIT(mt->touches, slot) 1682dc7188eSVladimir Kondratyev if (evdev_mt_get_value(evdev, slot, ABS_MT_TRACKING_ID) == 1692dc7188eSVladimir Kondratyev tracking_id) 1702b3f6d66SOleksandr Tymoshenko return (slot); 1712b3f6d66SOleksandr Tymoshenko /* 1722dc7188eSVladimir Kondratyev * Do not allow allocation of new slot in a place of just 1732dc7188eSVladimir Kondratyev * released one within the same report. 1742b3f6d66SOleksandr Tymoshenko */ 1752dc7188eSVladimir Kondratyev return (ffc_slot(evdev, mt->touches | mt->frame)); 1762b3f6d66SOleksandr Tymoshenko } 1772b3f6d66SOleksandr Tymoshenko 1782b3f6d66SOleksandr Tymoshenko void 1792b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(struct evdev_dev *evdev) 1802b3f6d66SOleksandr Tymoshenko { 18198a7606bSVladimir Kondratyev int i; 1822b3f6d66SOleksandr Tymoshenko 1832b3f6d66SOleksandr Tymoshenko if (evdev->ev_absinfo == NULL) 1842b3f6d66SOleksandr Tymoshenko return; 1852b3f6d66SOleksandr Tymoshenko 1862b3f6d66SOleksandr Tymoshenko evdev_support_event(evdev, EV_KEY); 1872b3f6d66SOleksandr Tymoshenko evdev_support_key(evdev, BTN_TOUCH); 1882b3f6d66SOleksandr Tymoshenko 1892b3f6d66SOleksandr Tymoshenko /* Touchscreens should not advertise tap tool capabilities */ 1902b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 1912b3f6d66SOleksandr Tymoshenko evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1); 1922b3f6d66SOleksandr Tymoshenko 1932b3f6d66SOleksandr Tymoshenko /* Echo 0-th MT-slot as ST-slot */ 1942b3f6d66SOleksandr Tymoshenko for (i = 0; i < nitems(evdev_mtstmap); i++) 1952b3f6d66SOleksandr Tymoshenko if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][0])) 1962b3f6d66SOleksandr Tymoshenko evdev_support_abs(evdev, evdev_mtstmap[i][1], 1972b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].minimum, 1982b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].maximum, 1992b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].fuzz, 2002b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].flat, 2012b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].resolution); 2022b3f6d66SOleksandr Tymoshenko } 2032b3f6d66SOleksandr Tymoshenko 2042b3f6d66SOleksandr Tymoshenko static void 20598a7606bSVladimir Kondratyev evdev_mt_send_st_compat(struct evdev_dev *evdev) 2062b3f6d66SOleksandr Tymoshenko { 2072dc7188eSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 208*fbe17f90SVladimir Kondratyev int nfingers, i, st_slot; 2092b3f6d66SOleksandr Tymoshenko 2102b3f6d66SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 2112b3f6d66SOleksandr Tymoshenko 2122dc7188eSVladimir Kondratyev nfingers = bitcount(mt->touches); 2132b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0); 2142b3f6d66SOleksandr Tymoshenko 215*fbe17f90SVladimir Kondratyev /* Send first active MT-slot state as single touch report */ 216*fbe17f90SVladimir Kondratyev st_slot = ffs(mt->touches) - 1; 217*fbe17f90SVladimir Kondratyev if (st_slot != -1) 2182b3f6d66SOleksandr Tymoshenko for (i = 0; i < nitems(evdev_mtstmap); i++) 2192b3f6d66SOleksandr Tymoshenko if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][1])) 2202b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, 2212b3f6d66SOleksandr Tymoshenko evdev_mtstmap[i][1], 222*fbe17f90SVladimir Kondratyev evdev_mt_get_value(evdev, st_slot, 2232b3f6d66SOleksandr Tymoshenko evdev_mtstmap[i][0])); 2242b3f6d66SOleksandr Tymoshenko 2252b3f6d66SOleksandr Tymoshenko /* Touchscreens should not report tool taps */ 2262b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 2272b3f6d66SOleksandr Tymoshenko evdev_send_nfingers(evdev, nfingers); 2282b3f6d66SOleksandr Tymoshenko 2292b3f6d66SOleksandr Tymoshenko if (nfingers == 0) 2302b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0); 2312b3f6d66SOleksandr Tymoshenko } 2322b3f6d66SOleksandr Tymoshenko 2332b3f6d66SOleksandr Tymoshenko void 2342b3f6d66SOleksandr Tymoshenko evdev_push_mt_compat(struct evdev_dev *evdev) 2352b3f6d66SOleksandr Tymoshenko { 2362b3f6d66SOleksandr Tymoshenko 2374c0a4665SVladimir Kondratyev EVDEV_ENTER(evdev); 23898a7606bSVladimir Kondratyev evdev_mt_send_st_compat(evdev); 2394c0a4665SVladimir Kondratyev EVDEV_EXIT(evdev); 2402b3f6d66SOleksandr Tymoshenko } 241c736a757SOleksandr Tymoshenko 24298a7606bSVladimir Kondratyev static void 24398a7606bSVladimir Kondratyev evdev_mt_send_autorel(struct evdev_dev *evdev) 244c736a757SOleksandr Tymoshenko { 24598a7606bSVladimir Kondratyev struct evdev_mt *mt = evdev->ev_mt; 24698a7606bSVladimir Kondratyev int slot; 247c736a757SOleksandr Tymoshenko 248c736a757SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 249c736a757SOleksandr Tymoshenko 2502dc7188eSVladimir Kondratyev FOREACHBIT(mt->touches & ~mt->frame, slot) { 251c736a757SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot); 2522dc7188eSVladimir Kondratyev evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID, -1); 253c736a757SOleksandr Tymoshenko } 254c736a757SOleksandr Tymoshenko } 25598a7606bSVladimir Kondratyev 25698a7606bSVladimir Kondratyev void 25798a7606bSVladimir Kondratyev evdev_mt_push_autorel(struct evdev_dev *evdev) 25898a7606bSVladimir Kondratyev { 25998a7606bSVladimir Kondratyev EVDEV_ENTER(evdev); 26098a7606bSVladimir Kondratyev evdev_mt_send_autorel(evdev); 26198a7606bSVladimir Kondratyev EVDEV_EXIT(evdev); 26298a7606bSVladimir Kondratyev } 263