The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/evdev/evdev_mt.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 13ec3705c74dbff8bfa85af8562b11ee


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.