1*2b3f6d66SOleksandr Tymoshenko /*- 2*2b3f6d66SOleksandr Tymoshenko * Copyright (c) 2016 Vladimir Kondratyev <wulf@cicgroup.ru> 3*2b3f6d66SOleksandr Tymoshenko * All rights reserved. 4*2b3f6d66SOleksandr Tymoshenko * 5*2b3f6d66SOleksandr Tymoshenko * Redistribution and use in source and binary forms, with or without 6*2b3f6d66SOleksandr Tymoshenko * modification, are permitted provided that the following conditions 7*2b3f6d66SOleksandr Tymoshenko * are met: 8*2b3f6d66SOleksandr Tymoshenko * 1. Redistributions of source code must retain the above copyright 9*2b3f6d66SOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer. 10*2b3f6d66SOleksandr Tymoshenko * 2. Redistributions in binary form must reproduce the above copyright 11*2b3f6d66SOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer in the 12*2b3f6d66SOleksandr Tymoshenko * documentation and/or other materials provided with the distribution. 13*2b3f6d66SOleksandr Tymoshenko * 14*2b3f6d66SOleksandr Tymoshenko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*2b3f6d66SOleksandr Tymoshenko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*2b3f6d66SOleksandr Tymoshenko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*2b3f6d66SOleksandr Tymoshenko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*2b3f6d66SOleksandr Tymoshenko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*2b3f6d66SOleksandr Tymoshenko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*2b3f6d66SOleksandr Tymoshenko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*2b3f6d66SOleksandr Tymoshenko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*2b3f6d66SOleksandr Tymoshenko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*2b3f6d66SOleksandr Tymoshenko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*2b3f6d66SOleksandr Tymoshenko * SUCH DAMAGE. 25*2b3f6d66SOleksandr Tymoshenko * 26*2b3f6d66SOleksandr Tymoshenko * $FreeBSD$ 27*2b3f6d66SOleksandr Tymoshenko */ 28*2b3f6d66SOleksandr Tymoshenko 29*2b3f6d66SOleksandr Tymoshenko #include <sys/param.h> 30*2b3f6d66SOleksandr Tymoshenko #include <sys/malloc.h> 31*2b3f6d66SOleksandr Tymoshenko #include <sys/lock.h> 32*2b3f6d66SOleksandr Tymoshenko #include <sys/mutex.h> 33*2b3f6d66SOleksandr Tymoshenko #include <sys/systm.h> 34*2b3f6d66SOleksandr Tymoshenko 35*2b3f6d66SOleksandr Tymoshenko #include <dev/evdev/input.h> 36*2b3f6d66SOleksandr Tymoshenko #include <dev/evdev/evdev.h> 37*2b3f6d66SOleksandr Tymoshenko #include <dev/evdev/evdev_private.h> 38*2b3f6d66SOleksandr Tymoshenko 39*2b3f6d66SOleksandr Tymoshenko #ifdef DEBUG 40*2b3f6d66SOleksandr Tymoshenko #define debugf(fmt, args...) printf("evdev: " fmt "\n", ##args) 41*2b3f6d66SOleksandr Tymoshenko #else 42*2b3f6d66SOleksandr Tymoshenko #define debugf(fmt, args...) 43*2b3f6d66SOleksandr Tymoshenko #endif 44*2b3f6d66SOleksandr Tymoshenko 45*2b3f6d66SOleksandr Tymoshenko static uint16_t evdev_fngmap[] = { 46*2b3f6d66SOleksandr Tymoshenko BTN_TOOL_FINGER, 47*2b3f6d66SOleksandr Tymoshenko BTN_TOOL_DOUBLETAP, 48*2b3f6d66SOleksandr Tymoshenko BTN_TOOL_TRIPLETAP, 49*2b3f6d66SOleksandr Tymoshenko BTN_TOOL_QUADTAP, 50*2b3f6d66SOleksandr Tymoshenko BTN_TOOL_QUINTTAP, 51*2b3f6d66SOleksandr Tymoshenko }; 52*2b3f6d66SOleksandr Tymoshenko 53*2b3f6d66SOleksandr Tymoshenko static uint16_t evdev_mtstmap[][2] = { 54*2b3f6d66SOleksandr Tymoshenko { ABS_MT_POSITION_X, ABS_X }, 55*2b3f6d66SOleksandr Tymoshenko { ABS_MT_POSITION_Y, ABS_Y }, 56*2b3f6d66SOleksandr Tymoshenko { ABS_MT_PRESSURE, ABS_PRESSURE }, 57*2b3f6d66SOleksandr Tymoshenko { ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH }, 58*2b3f6d66SOleksandr Tymoshenko }; 59*2b3f6d66SOleksandr Tymoshenko 60*2b3f6d66SOleksandr Tymoshenko struct evdev_mt_slot { 61*2b3f6d66SOleksandr Tymoshenko uint64_t ev_report; 62*2b3f6d66SOleksandr Tymoshenko int32_t ev_mt_states[MT_CNT]; 63*2b3f6d66SOleksandr Tymoshenko }; 64*2b3f6d66SOleksandr Tymoshenko 65*2b3f6d66SOleksandr Tymoshenko struct evdev_mt { 66*2b3f6d66SOleksandr Tymoshenko int32_t ev_mt_last_reported_slot; 67*2b3f6d66SOleksandr Tymoshenko struct evdev_mt_slot ev_mt_slots[]; 68*2b3f6d66SOleksandr Tymoshenko }; 69*2b3f6d66SOleksandr Tymoshenko 70*2b3f6d66SOleksandr Tymoshenko void 71*2b3f6d66SOleksandr Tymoshenko evdev_mt_init(struct evdev_dev *evdev) 72*2b3f6d66SOleksandr Tymoshenko { 73*2b3f6d66SOleksandr Tymoshenko int32_t slot, slots; 74*2b3f6d66SOleksandr Tymoshenko 75*2b3f6d66SOleksandr Tymoshenko slots = MAXIMAL_MT_SLOT(evdev) + 1; 76*2b3f6d66SOleksandr Tymoshenko 77*2b3f6d66SOleksandr Tymoshenko evdev->ev_mt = malloc(offsetof(struct evdev_mt, ev_mt_slots) + 78*2b3f6d66SOleksandr Tymoshenko sizeof(struct evdev_mt_slot) * slots, M_EVDEV, M_WAITOK | M_ZERO); 79*2b3f6d66SOleksandr Tymoshenko 80*2b3f6d66SOleksandr Tymoshenko /* Initialize multitouch protocol type B states */ 81*2b3f6d66SOleksandr Tymoshenko for (slot = 0; slot < slots; slot++) { 82*2b3f6d66SOleksandr Tymoshenko /* 83*2b3f6d66SOleksandr Tymoshenko * .ev_report should not be initialized to initial value of 84*2b3f6d66SOleksandr Tymoshenko * report counter (0) as it brokes free slot detection in 85*2b3f6d66SOleksandr Tymoshenko * evdev_get_mt_slot_by_tracking_id. So initialize it to -1 86*2b3f6d66SOleksandr Tymoshenko */ 87*2b3f6d66SOleksandr Tymoshenko evdev->ev_mt->ev_mt_slots[slot] = (struct evdev_mt_slot) { 88*2b3f6d66SOleksandr Tymoshenko .ev_report = 0xFFFFFFFFFFFFFFFFULL, 89*2b3f6d66SOleksandr Tymoshenko .ev_mt_states[ABS_MT_INDEX(ABS_MT_TRACKING_ID)] = -1, 90*2b3f6d66SOleksandr Tymoshenko }; 91*2b3f6d66SOleksandr Tymoshenko } 92*2b3f6d66SOleksandr Tymoshenko 93*2b3f6d66SOleksandr Tymoshenko if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT)) 94*2b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(evdev); 95*2b3f6d66SOleksandr Tymoshenko } 96*2b3f6d66SOleksandr Tymoshenko 97*2b3f6d66SOleksandr Tymoshenko void 98*2b3f6d66SOleksandr Tymoshenko evdev_mt_free(struct evdev_dev *evdev) 99*2b3f6d66SOleksandr Tymoshenko { 100*2b3f6d66SOleksandr Tymoshenko 101*2b3f6d66SOleksandr Tymoshenko free(evdev->ev_mt, M_EVDEV); 102*2b3f6d66SOleksandr Tymoshenko } 103*2b3f6d66SOleksandr Tymoshenko 104*2b3f6d66SOleksandr Tymoshenko int32_t 105*2b3f6d66SOleksandr Tymoshenko evdev_get_last_mt_slot(struct evdev_dev *evdev) 106*2b3f6d66SOleksandr Tymoshenko { 107*2b3f6d66SOleksandr Tymoshenko 108*2b3f6d66SOleksandr Tymoshenko return (evdev->ev_mt->ev_mt_last_reported_slot); 109*2b3f6d66SOleksandr Tymoshenko } 110*2b3f6d66SOleksandr Tymoshenko 111*2b3f6d66SOleksandr Tymoshenko void 112*2b3f6d66SOleksandr Tymoshenko evdev_set_last_mt_slot(struct evdev_dev *evdev, int32_t slot) 113*2b3f6d66SOleksandr Tymoshenko { 114*2b3f6d66SOleksandr Tymoshenko 115*2b3f6d66SOleksandr Tymoshenko evdev->ev_mt->ev_mt_last_reported_slot = slot; 116*2b3f6d66SOleksandr Tymoshenko } 117*2b3f6d66SOleksandr Tymoshenko 118*2b3f6d66SOleksandr Tymoshenko inline int32_t 119*2b3f6d66SOleksandr Tymoshenko evdev_get_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code) 120*2b3f6d66SOleksandr Tymoshenko { 121*2b3f6d66SOleksandr Tymoshenko 122*2b3f6d66SOleksandr Tymoshenko return (evdev->ev_mt-> 123*2b3f6d66SOleksandr Tymoshenko ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)]); 124*2b3f6d66SOleksandr Tymoshenko } 125*2b3f6d66SOleksandr Tymoshenko 126*2b3f6d66SOleksandr Tymoshenko inline void 127*2b3f6d66SOleksandr Tymoshenko evdev_set_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code, 128*2b3f6d66SOleksandr Tymoshenko int32_t value) 129*2b3f6d66SOleksandr Tymoshenko { 130*2b3f6d66SOleksandr Tymoshenko 131*2b3f6d66SOleksandr Tymoshenko if (code == ABS_MT_TRACKING_ID && value == -1) 132*2b3f6d66SOleksandr Tymoshenko evdev->ev_mt->ev_mt_slots[slot].ev_report = 133*2b3f6d66SOleksandr Tymoshenko evdev->ev_report_count; 134*2b3f6d66SOleksandr Tymoshenko 135*2b3f6d66SOleksandr Tymoshenko evdev->ev_mt->ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)] = 136*2b3f6d66SOleksandr Tymoshenko value; 137*2b3f6d66SOleksandr Tymoshenko } 138*2b3f6d66SOleksandr Tymoshenko 139*2b3f6d66SOleksandr Tymoshenko int32_t 140*2b3f6d66SOleksandr Tymoshenko evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id) 141*2b3f6d66SOleksandr Tymoshenko { 142*2b3f6d66SOleksandr Tymoshenko int32_t tr_id, slot, free_slot = -1; 143*2b3f6d66SOleksandr Tymoshenko 144*2b3f6d66SOleksandr Tymoshenko for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) { 145*2b3f6d66SOleksandr Tymoshenko tr_id = evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID); 146*2b3f6d66SOleksandr Tymoshenko if (tr_id == tracking_id) 147*2b3f6d66SOleksandr Tymoshenko return (slot); 148*2b3f6d66SOleksandr Tymoshenko /* 149*2b3f6d66SOleksandr Tymoshenko * Its possible that slot will be reassigned in a place of just 150*2b3f6d66SOleksandr Tymoshenko * released one within the same report. To avoid this compare 151*2b3f6d66SOleksandr Tymoshenko * report counter with slot`s report number updated with each 152*2b3f6d66SOleksandr Tymoshenko * ABS_MT_TRACKING_ID change. 153*2b3f6d66SOleksandr Tymoshenko */ 154*2b3f6d66SOleksandr Tymoshenko if (free_slot == -1 && tr_id == -1 && 155*2b3f6d66SOleksandr Tymoshenko evdev->ev_mt->ev_mt_slots[slot].ev_report != 156*2b3f6d66SOleksandr Tymoshenko evdev->ev_report_count) 157*2b3f6d66SOleksandr Tymoshenko free_slot = slot; 158*2b3f6d66SOleksandr Tymoshenko } 159*2b3f6d66SOleksandr Tymoshenko 160*2b3f6d66SOleksandr Tymoshenko return (free_slot); 161*2b3f6d66SOleksandr Tymoshenko } 162*2b3f6d66SOleksandr Tymoshenko 163*2b3f6d66SOleksandr Tymoshenko void 164*2b3f6d66SOleksandr Tymoshenko evdev_support_nfingers(struct evdev_dev *evdev, int32_t nfingers) 165*2b3f6d66SOleksandr Tymoshenko { 166*2b3f6d66SOleksandr Tymoshenko int32_t i; 167*2b3f6d66SOleksandr Tymoshenko 168*2b3f6d66SOleksandr Tymoshenko for (i = 0; i < MIN(nitems(evdev_fngmap), nfingers); i++) 169*2b3f6d66SOleksandr Tymoshenko evdev_support_key(evdev, evdev_fngmap[i]); 170*2b3f6d66SOleksandr Tymoshenko } 171*2b3f6d66SOleksandr Tymoshenko 172*2b3f6d66SOleksandr Tymoshenko void 173*2b3f6d66SOleksandr Tymoshenko evdev_support_mt_compat(struct evdev_dev *evdev) 174*2b3f6d66SOleksandr Tymoshenko { 175*2b3f6d66SOleksandr Tymoshenko int32_t i; 176*2b3f6d66SOleksandr Tymoshenko 177*2b3f6d66SOleksandr Tymoshenko if (evdev->ev_absinfo == NULL) 178*2b3f6d66SOleksandr Tymoshenko return; 179*2b3f6d66SOleksandr Tymoshenko 180*2b3f6d66SOleksandr Tymoshenko evdev_support_event(evdev, EV_KEY); 181*2b3f6d66SOleksandr Tymoshenko evdev_support_key(evdev, BTN_TOUCH); 182*2b3f6d66SOleksandr Tymoshenko 183*2b3f6d66SOleksandr Tymoshenko /* Touchscreens should not advertise tap tool capabilities */ 184*2b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 185*2b3f6d66SOleksandr Tymoshenko evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1); 186*2b3f6d66SOleksandr Tymoshenko 187*2b3f6d66SOleksandr Tymoshenko /* Echo 0-th MT-slot as ST-slot */ 188*2b3f6d66SOleksandr Tymoshenko for (i = 0; i < nitems(evdev_mtstmap); i++) 189*2b3f6d66SOleksandr Tymoshenko if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][0])) 190*2b3f6d66SOleksandr Tymoshenko evdev_support_abs(evdev, evdev_mtstmap[i][1], 191*2b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].value, 192*2b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].minimum, 193*2b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].maximum, 194*2b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].fuzz, 195*2b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].flat, 196*2b3f6d66SOleksandr Tymoshenko evdev->ev_absinfo[evdev_mtstmap[i][0]].resolution); 197*2b3f6d66SOleksandr Tymoshenko } 198*2b3f6d66SOleksandr Tymoshenko 199*2b3f6d66SOleksandr Tymoshenko static int32_t 200*2b3f6d66SOleksandr Tymoshenko evdev_count_fingers(struct evdev_dev *evdev) 201*2b3f6d66SOleksandr Tymoshenko { 202*2b3f6d66SOleksandr Tymoshenko int32_t nfingers = 0, i; 203*2b3f6d66SOleksandr Tymoshenko 204*2b3f6d66SOleksandr Tymoshenko for (i = 0; i <= MAXIMAL_MT_SLOT(evdev); i++) 205*2b3f6d66SOleksandr Tymoshenko if (evdev_get_mt_value(evdev, i, ABS_MT_TRACKING_ID) != -1) 206*2b3f6d66SOleksandr Tymoshenko nfingers++; 207*2b3f6d66SOleksandr Tymoshenko 208*2b3f6d66SOleksandr Tymoshenko return (nfingers); 209*2b3f6d66SOleksandr Tymoshenko } 210*2b3f6d66SOleksandr Tymoshenko 211*2b3f6d66SOleksandr Tymoshenko static void 212*2b3f6d66SOleksandr Tymoshenko evdev_send_nfingers(struct evdev_dev *evdev, int32_t nfingers) 213*2b3f6d66SOleksandr Tymoshenko { 214*2b3f6d66SOleksandr Tymoshenko int32_t i; 215*2b3f6d66SOleksandr Tymoshenko 216*2b3f6d66SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 217*2b3f6d66SOleksandr Tymoshenko 218*2b3f6d66SOleksandr Tymoshenko if (nfingers > nitems(evdev_fngmap)) 219*2b3f6d66SOleksandr Tymoshenko nfingers = nitems(evdev_fngmap); 220*2b3f6d66SOleksandr Tymoshenko 221*2b3f6d66SOleksandr Tymoshenko for (i = 0; i < nitems(evdev_fngmap); i++) 222*2b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_KEY, evdev_fngmap[i], 223*2b3f6d66SOleksandr Tymoshenko nfingers == i + 1); 224*2b3f6d66SOleksandr Tymoshenko } 225*2b3f6d66SOleksandr Tymoshenko 226*2b3f6d66SOleksandr Tymoshenko void 227*2b3f6d66SOleksandr Tymoshenko evdev_push_nfingers(struct evdev_dev *evdev, int32_t nfingers) 228*2b3f6d66SOleksandr Tymoshenko { 229*2b3f6d66SOleksandr Tymoshenko 230*2b3f6d66SOleksandr Tymoshenko EVDEV_LOCK(evdev); 231*2b3f6d66SOleksandr Tymoshenko evdev_send_nfingers(evdev, nfingers); 232*2b3f6d66SOleksandr Tymoshenko EVDEV_UNLOCK(evdev); 233*2b3f6d66SOleksandr Tymoshenko } 234*2b3f6d66SOleksandr Tymoshenko 235*2b3f6d66SOleksandr Tymoshenko void 236*2b3f6d66SOleksandr Tymoshenko evdev_send_mt_compat(struct evdev_dev *evdev) 237*2b3f6d66SOleksandr Tymoshenko { 238*2b3f6d66SOleksandr Tymoshenko int32_t nfingers, i; 239*2b3f6d66SOleksandr Tymoshenko 240*2b3f6d66SOleksandr Tymoshenko EVDEV_LOCK_ASSERT(evdev); 241*2b3f6d66SOleksandr Tymoshenko 242*2b3f6d66SOleksandr Tymoshenko nfingers = evdev_count_fingers(evdev); 243*2b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0); 244*2b3f6d66SOleksandr Tymoshenko 245*2b3f6d66SOleksandr Tymoshenko if (evdev_get_mt_value(evdev, 0, ABS_MT_TRACKING_ID) != -1) 246*2b3f6d66SOleksandr Tymoshenko /* Echo 0-th MT-slot as ST-slot */ 247*2b3f6d66SOleksandr Tymoshenko for (i = 0; i < nitems(evdev_mtstmap); i++) 248*2b3f6d66SOleksandr Tymoshenko if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][1])) 249*2b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, 250*2b3f6d66SOleksandr Tymoshenko evdev_mtstmap[i][1], 251*2b3f6d66SOleksandr Tymoshenko evdev_get_mt_value(evdev, 0, 252*2b3f6d66SOleksandr Tymoshenko evdev_mtstmap[i][0])); 253*2b3f6d66SOleksandr Tymoshenko 254*2b3f6d66SOleksandr Tymoshenko /* Touchscreens should not report tool taps */ 255*2b3f6d66SOleksandr Tymoshenko if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT)) 256*2b3f6d66SOleksandr Tymoshenko evdev_send_nfingers(evdev, nfingers); 257*2b3f6d66SOleksandr Tymoshenko 258*2b3f6d66SOleksandr Tymoshenko if (nfingers == 0) 259*2b3f6d66SOleksandr Tymoshenko evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0); 260*2b3f6d66SOleksandr Tymoshenko } 261*2b3f6d66SOleksandr Tymoshenko 262*2b3f6d66SOleksandr Tymoshenko void 263*2b3f6d66SOleksandr Tymoshenko evdev_push_mt_compat(struct evdev_dev *evdev) 264*2b3f6d66SOleksandr Tymoshenko { 265*2b3f6d66SOleksandr Tymoshenko 266*2b3f6d66SOleksandr Tymoshenko EVDEV_LOCK(evdev); 267*2b3f6d66SOleksandr Tymoshenko evdev_send_mt_compat(evdev); 268*2b3f6d66SOleksandr Tymoshenko EVDEV_UNLOCK(evdev); 269*2b3f6d66SOleksandr Tymoshenko } 270