linux/drivers/input/input-mt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Input Multitouch Library
   4 *
   5 * Copyright (c) 2008-2010 Henrik Rydberg
   6 */
   7
   8#include <linux/input/mt.h>
   9#include <linux/export.h>
  10#include <linux/slab.h>
  11
  12#define TRKID_SGN       ((TRKID_MAX + 1) >> 1)
  13
  14static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src)
  15{
  16        if (dev->absinfo && test_bit(src, dev->absbit)) {
  17                dev->absinfo[dst] = dev->absinfo[src];
  18                dev->absinfo[dst].fuzz = 0;
  19                dev->absbit[BIT_WORD(dst)] |= BIT_MASK(dst);
  20        }
  21}
  22
  23/**
  24 * input_mt_init_slots() - initialize MT input slots
  25 * @dev: input device supporting MT events and finger tracking
  26 * @num_slots: number of slots used by the device
  27 * @flags: mt tasks to handle in core
  28 *
  29 * This function allocates all necessary memory for MT slot handling
  30 * in the input device, prepares the ABS_MT_SLOT and
  31 * ABS_MT_TRACKING_ID events for use and sets up appropriate buffers.
  32 * Depending on the flags set, it also performs pointer emulation and
  33 * frame synchronization.
  34 *
  35 * May be called repeatedly. Returns -EINVAL if attempting to
  36 * reinitialize with a different number of slots.
  37 */
  38int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
  39                        unsigned int flags)
  40{
  41        struct input_mt *mt = dev->mt;
  42        int i;
  43
  44        if (!num_slots)
  45                return 0;
  46        if (mt)
  47                return mt->num_slots != num_slots ? -EINVAL : 0;
  48
  49        mt = kzalloc(struct_size(mt, slots, num_slots), GFP_KERNEL);
  50        if (!mt)
  51                goto err_mem;
  52
  53        mt->num_slots = num_slots;
  54        mt->flags = flags;
  55        input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
  56        input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
  57
  58        if (flags & (INPUT_MT_POINTER | INPUT_MT_DIRECT)) {
  59                __set_bit(EV_KEY, dev->evbit);
  60                __set_bit(BTN_TOUCH, dev->keybit);
  61
  62                copy_abs(dev, ABS_X, ABS_MT_POSITION_X);
  63                copy_abs(dev, ABS_Y, ABS_MT_POSITION_Y);
  64                copy_abs(dev, ABS_PRESSURE, ABS_MT_PRESSURE);
  65        }
  66        if (flags & INPUT_MT_POINTER) {
  67                __set_bit(BTN_TOOL_FINGER, dev->keybit);
  68                __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
  69                if (num_slots >= 3)
  70                        __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
  71                if (num_slots >= 4)
  72                        __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
  73                if (num_slots >= 5)
  74                        __set_bit(BTN_TOOL_QUINTTAP, dev->keybit);
  75                __set_bit(INPUT_PROP_POINTER, dev->propbit);
  76        }
  77        if (flags & INPUT_MT_DIRECT)
  78                __set_bit(INPUT_PROP_DIRECT, dev->propbit);
  79        if (flags & INPUT_MT_SEMI_MT)
  80                __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
  81        if (flags & INPUT_MT_TRACK) {
  82                unsigned int n2 = num_slots * num_slots;
  83                mt->red = kcalloc(n2, sizeof(*mt->red), GFP_KERNEL);
  84                if (!mt->red)
  85                        goto err_mem;
  86        }
  87
  88        /* Mark slots as 'inactive' */
  89        for (i = 0; i < num_slots; i++)
  90                input_mt_set_value(&mt->slots[i], ABS_MT_TRACKING_ID, -1);
  91
  92        /* Mark slots as 'unused' */
  93        mt->frame = 1;
  94
  95        dev->mt = mt;
  96        return 0;
  97err_mem:
  98        kfree(mt);
  99        return -ENOMEM;
 100}
 101EXPORT_SYMBOL(input_mt_init_slots);
 102
 103/**
 104 * input_mt_destroy_slots() - frees the MT slots of the input device
 105 * @dev: input device with allocated MT slots
 106 *
 107 * This function is only needed in error path as the input core will
 108 * automatically free the MT slots when the device is destroyed.
 109 */
 110void input_mt_destroy_slots(struct input_dev *dev)
 111{
 112        if (dev->mt) {
 113                kfree(dev->mt->red);
 114                kfree(dev->mt);
 115        }
 116        dev->mt = NULL;
 117}
 118EXPORT_SYMBOL(input_mt_destroy_slots);
 119
 120/**
 121 * input_mt_report_slot_state() - report contact state
 122 * @dev: input device with allocated MT slots
 123 * @tool_type: the tool type to use in this slot
 124 * @active: true if contact is active, false otherwise
 125 *
 126 * Reports a contact via ABS_MT_TRACKING_ID, and optionally
 127 * ABS_MT_TOOL_TYPE. If active is true and the slot is currently
 128 * inactive, or if the tool type is changed, a new tracking id is
 129 * assigned to the slot. The tool type is only reported if the
 130 * corresponding absbit field is set.
 131 *
 132 * Returns true if contact is active.
 133 */
 134bool input_mt_report_slot_state(struct input_dev *dev,
 135                                unsigned int tool_type, bool active)
 136{
 137        struct input_mt *mt = dev->mt;
 138        struct input_mt_slot *slot;
 139        int id;
 140
 141        if (!mt)
 142                return false;
 143
 144        slot = &mt->slots[mt->slot];
 145        slot->frame = mt->frame;
 146
 147        if (!active) {
 148                input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
 149                return false;
 150        }
 151
 152        id = input_mt_get_value(slot, ABS_MT_TRACKING_ID);
 153        if (id < 0)
 154                id = input_mt_new_trkid(mt);
 155
 156        input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
 157        input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);
 158
 159        return true;
 160}
 161EXPORT_SYMBOL(input_mt_report_slot_state);
 162
 163/**
 164 * input_mt_report_finger_count() - report contact count
 165 * @dev: input device with allocated MT slots
 166 * @count: the number of contacts
 167 *
 168 * Reports the contact count via BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP,
 169 * BTN_TOOL_TRIPLETAP and BTN_TOOL_QUADTAP.
 170 *
 171 * The input core ensures only the KEY events already setup for
 172 * this device will produce output.
 173 */
 174void input_mt_report_finger_count(struct input_dev *dev, int count)
 175{
 176        input_event(dev, EV_KEY, BTN_TOOL_FINGER, count == 1);
 177        input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2);
 178        input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3);
 179        input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count == 4);
 180        input_event(dev, EV_KEY, BTN_TOOL_QUINTTAP, count == 5);
 181}
 182EXPORT_SYMBOL(input_mt_report_finger_count);
 183
 184/**
 185 * input_mt_report_pointer_emulation() - common pointer emulation
 186 * @dev: input device with allocated MT slots
 187 * @use_count: report number of active contacts as finger count
 188 *
 189 * Performs legacy pointer emulation via BTN_TOUCH, ABS_X, ABS_Y and
 190 * ABS_PRESSURE. Touchpad finger count is emulated if use_count is true.
 191 *
 192 * The input core ensures only the KEY and ABS axes already setup for
 193 * this device will produce output.
 194 */
 195void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
 196{
 197        struct input_mt *mt = dev->mt;
 198        struct input_mt_slot *oldest;
 199        int oldid, count, i;
 200
 201        if (!mt)
 202                return;
 203
 204        oldest = NULL;
 205        oldid = mt->trkid;
 206        count = 0;
 207
 208        for (i = 0; i < mt->num_slots; ++i) {
 209                struct input_mt_slot *ps = &mt->slots[i];
 210                int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
 211
 212                if (id < 0)
 213                        continue;
 214                if ((id - oldid) & TRKID_SGN) {
 215                        oldest = ps;
 216                        oldid = id;
 217                }
 218                count++;
 219        }
 220
 221        input_event(dev, EV_KEY, BTN_TOUCH, count > 0);
 222
 223        if (use_count) {
 224                if (count == 0 &&
 225                    !test_bit(ABS_MT_DISTANCE, dev->absbit) &&
 226                    test_bit(ABS_DISTANCE, dev->absbit) &&
 227                    input_abs_get_val(dev, ABS_DISTANCE) != 0) {
 228                        /*
 229                         * Force reporting BTN_TOOL_FINGER for devices that
 230                         * only report general hover (and not per-contact
 231                         * distance) when contact is in proximity but not
 232                         * on the surface.
 233                         */
 234                        count = 1;
 235                }
 236
 237                input_mt_report_finger_count(dev, count);
 238        }
 239
 240        if (oldest) {
 241                int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
 242                int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);
 243
 244                input_event(dev, EV_ABS, ABS_X, x);
 245                input_event(dev, EV_ABS, ABS_Y, y);
 246
 247                if (test_bit(ABS_MT_PRESSURE, dev->absbit)) {
 248                        int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
 249                        input_event(dev, EV_ABS, ABS_PRESSURE, p);
 250                }
 251        } else {
 252                if (test_bit(ABS_MT_PRESSURE, dev->absbit))
 253                        input_event(dev, EV_ABS, ABS_PRESSURE, 0);
 254        }
 255}
 256EXPORT_SYMBOL(input_mt_report_pointer_emulation);
 257
 258static void __input_mt_drop_unused(struct input_dev *dev, struct input_mt *mt)
 259{
 260        int i;
 261
 262        for (i = 0; i < mt->num_slots; i++) {
 263                if (!input_mt_is_used(mt, &mt->slots[i])) {
 264                        input_mt_slot(dev, i);
 265                        input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
 266                }
 267        }
 268}
 269
 270/**
 271 * input_mt_drop_unused() - Inactivate slots not seen in this frame
 272 * @dev: input device with allocated MT slots
 273 *
 274 * Lift all slots not seen since the last call to this function.
 275 */
 276void input_mt_drop_unused(struct input_dev *dev)
 277{
 278        struct input_mt *mt = dev->mt;
 279
 280        if (mt) {
 281                __input_mt_drop_unused(dev, mt);
 282                mt->frame++;
 283        }
 284}
 285EXPORT_SYMBOL(input_mt_drop_unused);
 286
 287/**
 288 * input_mt_sync_frame() - synchronize mt frame
 289 * @dev: input device with allocated MT slots
 290 *
 291 * Close the frame and prepare the internal state for a new one.
 292 * Depending on the flags, marks unused slots as inactive and performs
 293 * pointer emulation.
 294 */
 295void input_mt_sync_frame(struct input_dev *dev)
 296{
 297        struct input_mt *mt = dev->mt;
 298        bool use_count = false;
 299
 300        if (!mt)
 301                return;
 302
 303        if (mt->flags & INPUT_MT_DROP_UNUSED)
 304                __input_mt_drop_unused(dev, mt);
 305
 306        if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT))
 307                use_count = true;
 308
 309        input_mt_report_pointer_emulation(dev, use_count);
 310
 311        mt->frame++;
 312}
 313EXPORT_SYMBOL(input_mt_sync_frame);
 314
 315static int adjust_dual(int *begin, int step, int *end, int eq, int mu)
 316{
 317        int f, *p, s, c;
 318
 319        if (begin == end)
 320                return 0;
 321
 322        f = *begin;
 323        p = begin + step;
 324        s = p == end ? f + 1 : *p;
 325
 326        for (; p != end; p += step)
 327                if (*p < f)
 328                        s = f, f = *p;
 329                else if (*p < s)
 330                        s = *p;
 331
 332        c = (f + s + 1) / 2;
 333        if (c == 0 || (c > mu && (!eq || mu > 0)))
 334                return 0;
 335        /* Improve convergence for positive matrices by penalizing overcovers */
 336        if (s < 0 && mu <= 0)
 337                c *= 2;
 338
 339        for (p = begin; p != end; p += step)
 340                *p -= c;
 341
 342        return (c < s && s <= 0) || (f >= 0 && f < c);
 343}
 344
 345static void find_reduced_matrix(int *w, int nr, int nc, int nrc, int mu)
 346{
 347        int i, k, sum;
 348
 349        for (k = 0; k < nrc; k++) {
 350                for (i = 0; i < nr; i++)
 351                        adjust_dual(w + i, nr, w + i + nrc, nr <= nc, mu);
 352                sum = 0;
 353                for (i = 0; i < nrc; i += nr)
 354                        sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr, mu);
 355                if (!sum)
 356                        break;
 357        }
 358}
 359
 360static int input_mt_set_matrix(struct input_mt *mt,
 361                               const struct input_mt_pos *pos, int num_pos,
 362                               int mu)
 363{
 364        const struct input_mt_pos *p;
 365        struct input_mt_slot *s;
 366        int *w = mt->red;
 367        int x, y;
 368
 369        for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
 370                if (!input_mt_is_active(s))
 371                        continue;
 372                x = input_mt_get_value(s, ABS_MT_POSITION_X);
 373                y = input_mt_get_value(s, ABS_MT_POSITION_Y);
 374                for (p = pos; p != pos + num_pos; p++) {
 375                        int dx = x - p->x, dy = y - p->y;
 376                        *w++ = dx * dx + dy * dy - mu;
 377                }
 378        }
 379
 380        return w - mt->red;
 381}
 382
 383static void input_mt_set_slots(struct input_mt *mt,
 384                               int *slots, int num_pos)
 385{
 386        struct input_mt_slot *s;
 387        int *w = mt->red, j;
 388
 389        for (j = 0; j != num_pos; j++)
 390                slots[j] = -1;
 391
 392        for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
 393                if (!input_mt_is_active(s))
 394                        continue;
 395
 396                for (j = 0; j != num_pos; j++) {
 397                        if (w[j] < 0) {
 398                                slots[j] = s - mt->slots;
 399                                break;
 400                        }
 401                }
 402
 403                w += num_pos;
 404        }
 405
 406        for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
 407                if (input_mt_is_active(s))
 408                        continue;
 409
 410                for (j = 0; j != num_pos; j++) {
 411                        if (slots[j] < 0) {
 412                                slots[j] = s - mt->slots;
 413                                break;
 414                        }
 415                }
 416        }
 417}
 418
 419/**
 420 * input_mt_assign_slots() - perform a best-match assignment
 421 * @dev: input device with allocated MT slots
 422 * @slots: the slot assignment to be filled
 423 * @pos: the position array to match
 424 * @num_pos: number of positions
 425 * @dmax: maximum ABS_MT_POSITION displacement (zero for infinite)
 426 *
 427 * Performs a best match against the current contacts and returns
 428 * the slot assignment list. New contacts are assigned to unused
 429 * slots.
 430 *
 431 * The assignments are balanced so that all coordinate displacements are
 432 * below the euclidian distance dmax. If no such assignment can be found,
 433 * some contacts are assigned to unused slots.
 434 *
 435 * Returns zero on success, or negative error in case of failure.
 436 */
 437int input_mt_assign_slots(struct input_dev *dev, int *slots,
 438                          const struct input_mt_pos *pos, int num_pos,
 439                          int dmax)
 440{
 441        struct input_mt *mt = dev->mt;
 442        int mu = 2 * dmax * dmax;
 443        int nrc;
 444
 445        if (!mt || !mt->red)
 446                return -ENXIO;
 447        if (num_pos > mt->num_slots)
 448                return -EINVAL;
 449        if (num_pos < 1)
 450                return 0;
 451
 452        nrc = input_mt_set_matrix(mt, pos, num_pos, mu);
 453        find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc, mu);
 454        input_mt_set_slots(mt, slots, num_pos);
 455
 456        return 0;
 457}
 458EXPORT_SYMBOL(input_mt_assign_slots);
 459
 460/**
 461 * input_mt_get_slot_by_key() - return slot matching key
 462 * @dev: input device with allocated MT slots
 463 * @key: the key of the sought slot
 464 *
 465 * Returns the slot of the given key, if it exists, otherwise
 466 * set the key on the first unused slot and return.
 467 *
 468 * If no available slot can be found, -1 is returned.
 469 * Note that for this function to work properly, input_mt_sync_frame() has
 470 * to be called at each frame.
 471 */
 472int input_mt_get_slot_by_key(struct input_dev *dev, int key)
 473{
 474        struct input_mt *mt = dev->mt;
 475        struct input_mt_slot *s;
 476
 477        if (!mt)
 478                return -1;
 479
 480        for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
 481                if (input_mt_is_active(s) && s->key == key)
 482                        return s - mt->slots;
 483
 484        for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
 485                if (!input_mt_is_active(s) && !input_mt_is_used(mt, s)) {
 486                        s->key = key;
 487                        return s - mt->slots;
 488                }
 489
 490        return -1;
 491}
 492EXPORT_SYMBOL(input_mt_get_slot_by_key);
 493