1305706Sgonzo/*- 2324768Swulf * Copyright (c) 2016 Vladimir Kondratyev <wulf@FreeBSD.org> 3305706Sgonzo * All rights reserved. 4305706Sgonzo * 5305706Sgonzo * Redistribution and use in source and binary forms, with or without 6305706Sgonzo * modification, are permitted provided that the following conditions 7305706Sgonzo * are met: 8305706Sgonzo * 1. Redistributions of source code must retain the above copyright 9305706Sgonzo * notice, this list of conditions and the following disclaimer. 10305706Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 11305706Sgonzo * notice, this list of conditions and the following disclaimer in the 12305706Sgonzo * documentation and/or other materials provided with the distribution. 13305706Sgonzo * 14305706Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15305706Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16305706Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17305706Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18305706Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19305706Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20305706Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21305706Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22305706Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23305706Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24305706Sgonzo * SUCH DAMAGE. 25305706Sgonzo * 26305706Sgonzo * $FreeBSD: stable/11/sys/dev/evdev/evdev_mt.c 324768 2017-10-19 20:16:40Z wulf $ 27305706Sgonzo */ 28305706Sgonzo 29305706Sgonzo#include <sys/param.h> 30324768Swulf#include <sys/lock.h> 31305706Sgonzo#include <sys/malloc.h> 32305706Sgonzo#include <sys/mutex.h> 33305706Sgonzo#include <sys/systm.h> 34305706Sgonzo 35305706Sgonzo#include <dev/evdev/evdev.h> 36305706Sgonzo#include <dev/evdev/evdev_private.h> 37324768Swulf#include <dev/evdev/input.h> 38305706Sgonzo 39305706Sgonzo#ifdef DEBUG 40305706Sgonzo#define debugf(fmt, args...) printf("evdev: " fmt "\n", ##args) 41305706Sgonzo#else 42305706Sgonzo#define debugf(fmt, args...) 43305706Sgonzo#endif 44305706Sgonzo 45305706Sgonzostatic uint16_t evdev_fngmap[] = { 46305706Sgonzo BTN_TOOL_FINGER, 47305706Sgonzo BTN_TOOL_DOUBLETAP, 48305706Sgonzo BTN_TOOL_TRIPLETAP, 49305706Sgonzo BTN_TOOL_QUADTAP, 50305706Sgonzo BTN_TOOL_QUINTTAP, 51305706Sgonzo}; 52305706Sgonzo 53305706Sgonzostatic uint16_t evdev_mtstmap[][2] = { 54305706Sgonzo { ABS_MT_POSITION_X, ABS_X }, 55305706Sgonzo { ABS_MT_POSITION_Y, ABS_Y }, 56305706Sgonzo { ABS_MT_PRESSURE, ABS_PRESSURE }, 57305706Sgonzo { ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH }, 58305706Sgonzo}; 59305706Sgonzo 60305706Sgonzostruct evdev_mt_slot { 61305706Sgonzo uint64_t ev_report; 62305706Sgonzo int32_t ev_mt_states[MT_CNT]; 63305706Sgonzo}; 64305706Sgonzo 65305706Sgonzostruct evdev_mt { 66305706Sgonzo int32_t ev_mt_last_reported_slot; 67305706Sgonzo struct evdev_mt_slot ev_mt_slots[]; 68305706Sgonzo}; 69305706Sgonzo 70305706Sgonzovoid 71305706Sgonzoevdev_mt_init(struct evdev_dev *evdev) 72305706Sgonzo{ 73305706Sgonzo int32_t slot, slots; 74305706Sgonzo 75305706Sgonzo slots = MAXIMAL_MT_SLOT(evdev) + 1; 76305706Sgonzo 77305706Sgonzo evdev->ev_mt = malloc(offsetof(struct evdev_mt, ev_mt_slots) + 78305706Sgonzo sizeof(struct evdev_mt_slot) * slots, M_EVDEV, M_WAITOK | M_ZERO); 79305706Sgonzo 80305706Sgonzo /* Initialize multitouch protocol type B states */ 81305706Sgonzo for (slot = 0; slot < slots; slot++) { 82305706Sgonzo /* 83305706Sgonzo * .ev_report should not be initialized to initial value of 84305706Sgonzo * report counter (0) as it brokes free slot detection in 85305706Sgonzo * evdev_get_mt_slot_by_tracking_id. So initialize it to -1 86305706Sgonzo */ 87305706Sgonzo evdev->ev_mt->ev_mt_slots[slot] = (struct evdev_mt_slot) { 88305706Sgonzo .ev_report = 0xFFFFFFFFFFFFFFFFULL, 89305706Sgonzo .ev_mt_states[ABS_MT_INDEX(ABS_MT_TRACKING_ID)] = -1, 90305706Sgonzo }; 91305706Sgonzo } 92305706Sgonzo 93305706Sgonzo if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) 94305706Sgonzo evdev_support_mt_compat(evdev); 95305706Sgonzo} 96305706Sgonzo 97305706Sgonzovoid 98305706Sgonzoevdev_mt_free(struct evdev_dev *evdev) 99305706Sgonzo{ 100305706Sgonzo 101305706Sgonzo free(evdev->ev_mt, M_EVDEV); 102305706Sgonzo} 103305706Sgonzo 104305706Sgonzoint32_t 105305706Sgonzoevdev_get_last_mt_slot(struct evdev_dev *evdev) 106305706Sgonzo{ 107305706Sgonzo 108305706Sgonzo return (evdev->ev_mt->ev_mt_last_reported_slot); 109305706Sgonzo} 110305706Sgonzo 111305706Sgonzovoid 112305706Sgonzoevdev_set_last_mt_slot(struct evdev_dev *evdev, int32_t slot) 113305706Sgonzo{ 114305706Sgonzo 115307777Sgonzo evdev->ev_mt->ev_mt_slots[slot].ev_report = evdev->ev_report_count; 116305706Sgonzo evdev->ev_mt->ev_mt_last_reported_slot = slot; 117305706Sgonzo} 118305706Sgonzo 119305706Sgonzoinline int32_t 120305706Sgonzoevdev_get_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code) 121305706Sgonzo{ 122305706Sgonzo 123305706Sgonzo return (evdev->ev_mt-> 124305706Sgonzo ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)]); 125305706Sgonzo} 126305706Sgonzo 127305706Sgonzoinline void 128305706Sgonzoevdev_set_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code, 129305706Sgonzo int32_t value) 130305706Sgonzo{ 131305706Sgonzo 132305706Sgonzo evdev->ev_mt->ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)] = 133305706Sgonzo value; 134305706Sgonzo} 135305706Sgonzo 136305706Sgonzoint32_t 137305706Sgonzoevdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id) 138305706Sgonzo{ 139305706Sgonzo int32_t tr_id, slot, free_slot = -1; 140305706Sgonzo 141305706Sgonzo for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) { 142305706Sgonzo tr_id = evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID); 143305706Sgonzo if (tr_id == tracking_id) 144305706Sgonzo return (slot); 145305706Sgonzo /* 146305706Sgonzo * Its possible that slot will be reassigned in a place of just 147305706Sgonzo * released one within the same report. To avoid this compare 148305706Sgonzo * report counter with slot`s report number updated with each 149305706Sgonzo * ABS_MT_TRACKING_ID change. 150305706Sgonzo */ 151305706Sgonzo if (free_slot == -1 && tr_id == -1 && 152305706Sgonzo evdev->ev_mt->ev_mt_slots[slot].ev_report != 153305706Sgonzo evdev->ev_report_count) 154305706Sgonzo free_slot = slot; 155305706Sgonzo } 156305706Sgonzo 157305706Sgonzo return (free_slot); 158305706Sgonzo} 159305706Sgonzo 160305706Sgonzovoid 161305706Sgonzoevdev_support_nfingers(struct evdev_dev *evdev, int32_t nfingers) 162305706Sgonzo{ 163305706Sgonzo int32_t i; 164305706Sgonzo 165305706Sgonzo for (i = 0; i < MIN(nitems(evdev_fngmap), nfingers); i++) 166305706Sgonzo evdev_support_key(evdev, evdev_fngmap[i]); 167305706Sgonzo} 168305706Sgonzo 169305706Sgonzovoid 170305706Sgonzoevdev_support_mt_compat(struct evdev_dev *evdev) 171305706Sgonzo{ 172305706Sgonzo int32_t i; 173305706Sgonzo 174305706Sgonzo if (evdev->ev_absinfo == NULL) 175305706Sgonzo return; 176305706Sgonzo 177305706Sgonzo evdev_support_event(evdev, EV_KEY); 178305706Sgonzo evdev_support_key(evdev, BTN_TOUCH); 179305706Sgonzo 180305706Sgonzo /* Touchscreens should not advertise tap tool capabilities */ 181305706Sgonzo if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 182305706Sgonzo evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1); 183305706Sgonzo 184305706Sgonzo /* Echo 0-th MT-slot as ST-slot */ 185305706Sgonzo for (i = 0; i < nitems(evdev_mtstmap); i++) 186305706Sgonzo if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][0])) 187305706Sgonzo evdev_support_abs(evdev, evdev_mtstmap[i][1], 188305706Sgonzo evdev->ev_absinfo[evdev_mtstmap[i][0]].value, 189305706Sgonzo evdev->ev_absinfo[evdev_mtstmap[i][0]].minimum, 190305706Sgonzo evdev->ev_absinfo[evdev_mtstmap[i][0]].maximum, 191305706Sgonzo evdev->ev_absinfo[evdev_mtstmap[i][0]].fuzz, 192305706Sgonzo evdev->ev_absinfo[evdev_mtstmap[i][0]].flat, 193305706Sgonzo evdev->ev_absinfo[evdev_mtstmap[i][0]].resolution); 194305706Sgonzo} 195305706Sgonzo 196305706Sgonzostatic int32_t 197305706Sgonzoevdev_count_fingers(struct evdev_dev *evdev) 198305706Sgonzo{ 199305706Sgonzo int32_t nfingers = 0, i; 200305706Sgonzo 201305706Sgonzo for (i = 0; i <= MAXIMAL_MT_SLOT(evdev); i++) 202305706Sgonzo if (evdev_get_mt_value(evdev, i, ABS_MT_TRACKING_ID) != -1) 203305706Sgonzo nfingers++; 204305706Sgonzo 205305706Sgonzo return (nfingers); 206305706Sgonzo} 207305706Sgonzo 208305706Sgonzostatic void 209305706Sgonzoevdev_send_nfingers(struct evdev_dev *evdev, int32_t nfingers) 210305706Sgonzo{ 211305706Sgonzo int32_t i; 212305706Sgonzo 213305706Sgonzo EVDEV_LOCK_ASSERT(evdev); 214305706Sgonzo 215305706Sgonzo if (nfingers > nitems(evdev_fngmap)) 216305706Sgonzo nfingers = nitems(evdev_fngmap); 217305706Sgonzo 218305706Sgonzo for (i = 0; i < nitems(evdev_fngmap); i++) 219305706Sgonzo evdev_send_event(evdev, EV_KEY, evdev_fngmap[i], 220305706Sgonzo nfingers == i + 1); 221305706Sgonzo} 222305706Sgonzo 223305706Sgonzovoid 224305706Sgonzoevdev_push_nfingers(struct evdev_dev *evdev, int32_t nfingers) 225305706Sgonzo{ 226305706Sgonzo 227324768Swulf EVDEV_ENTER(evdev); 228305706Sgonzo evdev_send_nfingers(evdev, nfingers); 229324768Swulf EVDEV_EXIT(evdev); 230305706Sgonzo} 231305706Sgonzo 232305706Sgonzovoid 233305706Sgonzoevdev_send_mt_compat(struct evdev_dev *evdev) 234305706Sgonzo{ 235305706Sgonzo int32_t nfingers, i; 236305706Sgonzo 237305706Sgonzo EVDEV_LOCK_ASSERT(evdev); 238305706Sgonzo 239305706Sgonzo nfingers = evdev_count_fingers(evdev); 240305706Sgonzo evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0); 241305706Sgonzo 242305706Sgonzo if (evdev_get_mt_value(evdev, 0, ABS_MT_TRACKING_ID) != -1) 243305706Sgonzo /* Echo 0-th MT-slot as ST-slot */ 244305706Sgonzo for (i = 0; i < nitems(evdev_mtstmap); i++) 245305706Sgonzo if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][1])) 246305706Sgonzo evdev_send_event(evdev, EV_ABS, 247305706Sgonzo evdev_mtstmap[i][1], 248305706Sgonzo evdev_get_mt_value(evdev, 0, 249305706Sgonzo evdev_mtstmap[i][0])); 250305706Sgonzo 251305706Sgonzo /* Touchscreens should not report tool taps */ 252305706Sgonzo if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 253305706Sgonzo evdev_send_nfingers(evdev, nfingers); 254305706Sgonzo 255305706Sgonzo if (nfingers == 0) 256305706Sgonzo evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0); 257305706Sgonzo} 258305706Sgonzo 259305706Sgonzovoid 260305706Sgonzoevdev_push_mt_compat(struct evdev_dev *evdev) 261305706Sgonzo{ 262305706Sgonzo 263324768Swulf EVDEV_ENTER(evdev); 264305706Sgonzo evdev_send_mt_compat(evdev); 265324768Swulf EVDEV_EXIT(evdev); 266305706Sgonzo} 267307777Sgonzo 268307777Sgonzovoid 269307777Sgonzoevdev_send_mt_autorel(struct evdev_dev *evdev) 270307777Sgonzo{ 271307777Sgonzo int32_t slot; 272307777Sgonzo 273307777Sgonzo EVDEV_LOCK_ASSERT(evdev); 274307777Sgonzo 275307777Sgonzo for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) { 276307777Sgonzo if (evdev->ev_mt->ev_mt_slots[slot].ev_report != 277307777Sgonzo evdev->ev_report_count && 278307777Sgonzo evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID) != -1){ 279307777Sgonzo evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot); 280307777Sgonzo evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID, 281307777Sgonzo -1); 282307777Sgonzo } 283307777Sgonzo } 284307777Sgonzo} 285