root/drivers/input/input-mt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. copy_abs
  2. input_mt_init_slots
  3. input_mt_destroy_slots
  4. input_mt_report_slot_state
  5. input_mt_report_finger_count
  6. input_mt_report_pointer_emulation
  7. __input_mt_drop_unused
  8. input_mt_drop_unused
  9. input_mt_sync_frame
  10. adjust_dual
  11. find_reduced_matrix
  12. input_mt_set_matrix
  13. input_mt_set_slots
  14. input_mt_assign_slots
  15. input_mt_get_slot_by_key

   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 
  14 static 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  */
  38 int 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;
  97 err_mem:
  98         kfree(mt);
  99         return -ENOMEM;
 100 }
 101 EXPORT_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  */
 110 void 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 }
 118 EXPORT_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  */
 134 bool 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 }
 161 EXPORT_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  */
 174 void 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 }
 182 EXPORT_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  */
 195 void 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 }
 256 EXPORT_SYMBOL(input_mt_report_pointer_emulation);
 257 
 258 static 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  */
 276 void 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 }
 285 EXPORT_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  */
 295 void 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 }
 313 EXPORT_SYMBOL(input_mt_sync_frame);
 314 
 315 static 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 
 345 static 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 
 360 static 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 
 383 static 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  */
 437 int 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 }
 458 EXPORT_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  */
 472 int 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 }
 492 EXPORT_SYMBOL(input_mt_get_slot_by_key);

/* [<][>][^][v][top][bottom][index][help] */