LCOV - code coverage report
Current view: top level - drivers/input - input-mt.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 4 221 1.8 %
Date: 2022-04-01 14:35:51 Functions: 1 15 6.7 %
Branches: 1 160 0.6 %

           Branch data     Line data    Source code
       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                 :          0 : static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src)
      15                 :            : {
      16   [ #  #  #  # ]:          0 :         if (dev->absinfo && test_bit(src, dev->absbit)) {
      17                 :          0 :                 dev->absinfo[dst] = dev->absinfo[src];
      18                 :          0 :                 dev->absinfo[dst].fuzz = 0;
      19                 :          0 :                 dev->absbit[BIT_WORD(dst)] |= BIT_MASK(dst);
      20                 :            :         }
      21                 :          0 : }
      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                 :          0 : int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
      39                 :            :                         unsigned int flags)
      40                 :            : {
      41                 :          0 :         struct input_mt *mt = dev->mt;
      42                 :          0 :         int i;
      43                 :            : 
      44         [ #  # ]:          0 :         if (!num_slots)
      45                 :            :                 return 0;
      46         [ #  # ]:          0 :         if (mt)
      47         [ #  # ]:          0 :                 return mt->num_slots != num_slots ? -EINVAL : 0;
      48                 :            : 
      49         [ #  # ]:          0 :         mt = kzalloc(struct_size(mt, slots, num_slots), GFP_KERNEL);
      50         [ #  # ]:          0 :         if (!mt)
      51                 :          0 :                 goto err_mem;
      52                 :            : 
      53                 :          0 :         mt->num_slots = num_slots;
      54                 :          0 :         mt->flags = flags;
      55                 :          0 :         input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
      56                 :          0 :         input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
      57                 :            : 
      58         [ #  # ]:          0 :         if (flags & (INPUT_MT_POINTER | INPUT_MT_DIRECT)) {
      59                 :          0 :                 __set_bit(EV_KEY, dev->evbit);
      60                 :          0 :                 __set_bit(BTN_TOUCH, dev->keybit);
      61                 :            : 
      62                 :          0 :                 copy_abs(dev, ABS_X, ABS_MT_POSITION_X);
      63                 :          0 :                 copy_abs(dev, ABS_Y, ABS_MT_POSITION_Y);
      64                 :          0 :                 copy_abs(dev, ABS_PRESSURE, ABS_MT_PRESSURE);
      65                 :            :         }
      66         [ #  # ]:          0 :         if (flags & INPUT_MT_POINTER) {
      67                 :          0 :                 __set_bit(BTN_TOOL_FINGER, dev->keybit);
      68                 :          0 :                 __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
      69         [ #  # ]:          0 :                 if (num_slots >= 3)
      70                 :          0 :                         __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
      71         [ #  # ]:          0 :                 if (num_slots >= 4)
      72                 :          0 :                         __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
      73         [ #  # ]:          0 :                 if (num_slots >= 5)
      74                 :          0 :                         __set_bit(BTN_TOOL_QUINTTAP, dev->keybit);
      75                 :          0 :                 __set_bit(INPUT_PROP_POINTER, dev->propbit);
      76                 :            :         }
      77         [ #  # ]:          0 :         if (flags & INPUT_MT_DIRECT)
      78                 :          0 :                 __set_bit(INPUT_PROP_DIRECT, dev->propbit);
      79         [ #  # ]:          0 :         if (flags & INPUT_MT_SEMI_MT)
      80                 :          0 :                 __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
      81         [ #  # ]:          0 :         if (flags & INPUT_MT_TRACK) {
      82                 :          0 :                 unsigned int n2 = num_slots * num_slots;
      83                 :          0 :                 mt->red = kcalloc(n2, sizeof(*mt->red), GFP_KERNEL);
      84         [ #  # ]:          0 :                 if (!mt->red)
      85                 :          0 :                         goto err_mem;
      86                 :            :         }
      87                 :            : 
      88                 :            :         /* Mark slots as 'inactive' */
      89         [ #  # ]:          0 :         for (i = 0; i < num_slots; i++)
      90                 :          0 :                 input_mt_set_value(&mt->slots[i], ABS_MT_TRACKING_ID, -1);
      91                 :            : 
      92                 :            :         /* Mark slots as 'unused' */
      93                 :          0 :         mt->frame = 1;
      94                 :            : 
      95                 :          0 :         dev->mt = mt;
      96                 :          0 :         return 0;
      97                 :          0 : err_mem:
      98                 :          0 :         kfree(mt);
      99                 :          0 :         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                 :         21 : void input_mt_destroy_slots(struct input_dev *dev)
     111                 :            : {
     112         [ -  + ]:         21 :         if (dev->mt) {
     113                 :          0 :                 kfree(dev->mt->red);
     114                 :          0 :                 kfree(dev->mt);
     115                 :            :         }
     116                 :         21 :         dev->mt = NULL;
     117                 :         21 : }
     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                 :          0 : bool input_mt_report_slot_state(struct input_dev *dev,
     135                 :            :                                 unsigned int tool_type, bool active)
     136                 :            : {
     137                 :          0 :         struct input_mt *mt = dev->mt;
     138                 :          0 :         struct input_mt_slot *slot;
     139                 :          0 :         int id;
     140                 :            : 
     141         [ #  # ]:          0 :         if (!mt)
     142                 :            :                 return false;
     143                 :            : 
     144                 :          0 :         slot = &mt->slots[mt->slot];
     145                 :          0 :         slot->frame = mt->frame;
     146                 :            : 
     147         [ #  # ]:          0 :         if (!active) {
     148                 :          0 :                 input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
     149                 :          0 :                 return false;
     150                 :            :         }
     151                 :            : 
     152         [ #  # ]:          0 :         id = input_mt_get_value(slot, ABS_MT_TRACKING_ID);
     153         [ #  # ]:          0 :         if (id < 0)
     154                 :          0 :                 id = input_mt_new_trkid(mt);
     155                 :            : 
     156                 :          0 :         input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
     157                 :          0 :         input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);
     158                 :            : 
     159                 :          0 :         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                 :          0 : void input_mt_report_finger_count(struct input_dev *dev, int count)
     175                 :            : {
     176                 :          0 :         input_event(dev, EV_KEY, BTN_TOOL_FINGER, count == 1);
     177                 :          0 :         input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2);
     178                 :          0 :         input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3);
     179                 :          0 :         input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count == 4);
     180                 :          0 :         input_event(dev, EV_KEY, BTN_TOOL_QUINTTAP, count == 5);
     181                 :          0 : }
     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                 :          0 : void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
     196                 :            : {
     197                 :          0 :         struct input_mt *mt = dev->mt;
     198                 :          0 :         struct input_mt_slot *oldest;
     199                 :          0 :         int oldid, count, i;
     200                 :            : 
     201         [ #  # ]:          0 :         if (!mt)
     202                 :            :                 return;
     203                 :            : 
     204                 :          0 :         oldest = NULL;
     205                 :          0 :         oldid = mt->trkid;
     206                 :          0 :         count = 0;
     207                 :            : 
     208         [ #  # ]:          0 :         for (i = 0; i < mt->num_slots; ++i) {
     209                 :          0 :                 struct input_mt_slot *ps = &mt->slots[i];
     210         [ #  # ]:          0 :                 int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
     211                 :            : 
     212         [ #  # ]:          0 :                 if (id < 0)
     213                 :          0 :                         continue;
     214         [ #  # ]:          0 :                 if ((id - oldid) & TRKID_SGN) {
     215                 :          0 :                         oldest = ps;
     216                 :          0 :                         oldid = id;
     217                 :            :                 }
     218                 :          0 :                 count++;
     219                 :            :         }
     220                 :            : 
     221                 :          0 :         input_event(dev, EV_KEY, BTN_TOUCH, count > 0);
     222                 :            : 
     223         [ #  # ]:          0 :         if (use_count) {
     224   [ #  #  #  # ]:          0 :                 if (count == 0 &&
     225         [ #  # ]:          0 :                     !test_bit(ABS_MT_DISTANCE, dev->absbit) &&
     226         [ #  # ]:          0 :                     test_bit(ABS_DISTANCE, dev->absbit) &&
     227         [ #  # ]:          0 :                     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                 :          0 :                         count = 1;
     235                 :            :                 }
     236                 :            : 
     237                 :          0 :                 input_mt_report_finger_count(dev, count);
     238                 :            :         }
     239                 :            : 
     240         [ #  # ]:          0 :         if (oldest) {
     241                 :          0 :                 int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
     242                 :          0 :                 int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);
     243                 :            : 
     244                 :          0 :                 input_event(dev, EV_ABS, ABS_X, x);
     245                 :          0 :                 input_event(dev, EV_ABS, ABS_Y, y);
     246                 :            : 
     247         [ #  # ]:          0 :                 if (test_bit(ABS_MT_PRESSURE, dev->absbit)) {
     248                 :          0 :                         int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
     249                 :          0 :                         input_event(dev, EV_ABS, ABS_PRESSURE, p);
     250                 :            :                 }
     251                 :            :         } else {
     252         [ #  # ]:          0 :                 if (test_bit(ABS_MT_PRESSURE, dev->absbit))
     253                 :          0 :                         input_event(dev, EV_ABS, ABS_PRESSURE, 0);
     254                 :            :         }
     255                 :            : }
     256                 :            : EXPORT_SYMBOL(input_mt_report_pointer_emulation);
     257                 :            : 
     258                 :          0 : static void __input_mt_drop_unused(struct input_dev *dev, struct input_mt *mt)
     259                 :            : {
     260                 :          0 :         int i;
     261                 :            : 
     262         [ #  # ]:          0 :         for (i = 0; i < mt->num_slots; i++) {
     263         [ #  # ]:          0 :                 if (!input_mt_is_used(mt, &mt->slots[i])) {
     264                 :          0 :                         input_mt_slot(dev, i);
     265                 :          0 :                         input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
     266                 :            :                 }
     267                 :            :         }
     268                 :          0 : }
     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                 :          0 : void input_mt_drop_unused(struct input_dev *dev)
     277                 :            : {
     278                 :          0 :         struct input_mt *mt = dev->mt;
     279                 :            : 
     280         [ #  # ]:          0 :         if (mt) {
     281                 :          0 :                 __input_mt_drop_unused(dev, mt);
     282                 :          0 :                 mt->frame++;
     283                 :            :         }
     284                 :          0 : }
     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                 :          0 : void input_mt_sync_frame(struct input_dev *dev)
     296                 :            : {
     297                 :          0 :         struct input_mt *mt = dev->mt;
     298                 :          0 :         bool use_count = false;
     299                 :            : 
     300         [ #  # ]:          0 :         if (!mt)
     301                 :            :                 return;
     302                 :            : 
     303         [ #  # ]:          0 :         if (mt->flags & INPUT_MT_DROP_UNUSED)
     304                 :          0 :                 __input_mt_drop_unused(dev, mt);
     305                 :            : 
     306         [ #  # ]:          0 :         if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT))
     307                 :          0 :                 use_count = true;
     308                 :            : 
     309                 :          0 :         input_mt_report_pointer_emulation(dev, use_count);
     310                 :            : 
     311                 :          0 :         mt->frame++;
     312                 :            : }
     313                 :            : EXPORT_SYMBOL(input_mt_sync_frame);
     314                 :            : 
     315                 :          0 : static int adjust_dual(int *begin, int step, int *end, int eq, int mu)
     316                 :            : {
     317                 :          0 :         int f, *p, s, c;
     318                 :            : 
     319         [ #  # ]:          0 :         if (begin == end)
     320                 :            :                 return 0;
     321                 :            : 
     322                 :          0 :         f = *begin;
     323                 :          0 :         p = begin + step;
     324         [ #  # ]:          0 :         s = p == end ? f + 1 : *p;
     325                 :            : 
     326         [ #  # ]:          0 :         for (; p != end; p += step)
     327         [ #  # ]:          0 :                 if (*p < f)
     328                 :            :                         s = f, f = *p;
     329                 :          0 :                 else if (*p < s)
     330                 :            :                         s = *p;
     331                 :            : 
     332                 :          0 :         c = (f + s + 1) / 2;
     333   [ #  #  #  #  :          0 :         if (c == 0 || (c > mu && (!eq || mu > 0)))
                   #  # ]
     334                 :            :                 return 0;
     335                 :            :         /* Improve convergence for positive matrices by penalizing overcovers */
     336         [ #  # ]:          0 :         if (s < 0 && mu <= 0)
     337                 :          0 :                 c *= 2;
     338                 :            : 
     339         [ #  # ]:          0 :         for (p = begin; p != end; p += step)
     340                 :          0 :                 *p -= c;
     341                 :            : 
     342   [ #  #  #  # ]:          0 :         return (c < s && s <= 0) || (f >= 0 && f < c);
     343                 :            : }
     344                 :            : 
     345                 :          0 : static void find_reduced_matrix(int *w, int nr, int nc, int nrc, int mu)
     346                 :            : {
     347                 :          0 :         int i, k, sum;
     348                 :            : 
     349         [ #  # ]:          0 :         for (k = 0; k < nrc; k++) {
     350         [ #  # ]:          0 :                 for (i = 0; i < nr; i++)
     351                 :          0 :                         adjust_dual(w + i, nr, w + i + nrc, nr <= nc, mu);
     352                 :            :                 sum = 0;
     353         [ #  # ]:          0 :                 for (i = 0; i < nrc; i += nr)
     354                 :          0 :                         sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr, mu);
     355         [ #  # ]:          0 :                 if (!sum)
     356                 :            :                         break;
     357                 :            :         }
     358                 :          0 : }
     359                 :            : 
     360                 :          0 : 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                 :          0 :         const struct input_mt_pos *p;
     365                 :          0 :         struct input_mt_slot *s;
     366                 :          0 :         int *w = mt->red;
     367                 :          0 :         int x, y;
     368                 :            : 
     369         [ #  # ]:          0 :         for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
     370         [ #  # ]:          0 :                 if (!input_mt_is_active(s))
     371                 :          0 :                         continue;
     372                 :          0 :                 x = input_mt_get_value(s, ABS_MT_POSITION_X);
     373                 :          0 :                 y = input_mt_get_value(s, ABS_MT_POSITION_Y);
     374         [ #  # ]:          0 :                 for (p = pos; p != pos + num_pos; p++) {
     375                 :          0 :                         int dx = x - p->x, dy = y - p->y;
     376                 :          0 :                         *w++ = dx * dx + dy * dy - mu;
     377                 :            :                 }
     378                 :            :         }
     379                 :            : 
     380                 :          0 :         return w - mt->red;
     381                 :            : }
     382                 :            : 
     383                 :          0 : static void input_mt_set_slots(struct input_mt *mt,
     384                 :            :                                int *slots, int num_pos)
     385                 :            : {
     386                 :          0 :         struct input_mt_slot *s;
     387                 :          0 :         int *w = mt->red, j;
     388                 :            : 
     389         [ #  # ]:          0 :         for (j = 0; j != num_pos; j++)
     390                 :          0 :                 slots[j] = -1;
     391                 :            : 
     392         [ #  # ]:          0 :         for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
     393         [ #  # ]:          0 :                 if (!input_mt_is_active(s))
     394                 :          0 :                         continue;
     395                 :            : 
     396         [ #  # ]:          0 :                 for (j = 0; j != num_pos; j++) {
     397         [ #  # ]:          0 :                         if (w[j] < 0) {
     398                 :          0 :                                 slots[j] = s - mt->slots;
     399                 :          0 :                                 break;
     400                 :            :                         }
     401                 :            :                 }
     402                 :            : 
     403                 :          0 :                 w += num_pos;
     404                 :            :         }
     405                 :            : 
     406         [ #  # ]:          0 :         for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
     407         [ #  # ]:          0 :                 if (input_mt_is_active(s))
     408                 :          0 :                         continue;
     409                 :            : 
     410         [ #  # ]:          0 :                 for (j = 0; j != num_pos; j++) {
     411         [ #  # ]:          0 :                         if (slots[j] < 0) {
     412                 :          0 :                                 slots[j] = s - mt->slots;
     413                 :          0 :                                 break;
     414                 :            :                         }
     415                 :            :                 }
     416                 :            :         }
     417                 :          0 : }
     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                 :          0 : 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                 :          0 :         struct input_mt *mt = dev->mt;
     442                 :          0 :         int mu = 2 * dmax * dmax;
     443                 :          0 :         int nrc;
     444                 :            : 
     445   [ #  #  #  # ]:          0 :         if (!mt || !mt->red)
     446                 :            :                 return -ENXIO;
     447         [ #  # ]:          0 :         if (num_pos > mt->num_slots)
     448                 :            :                 return -EINVAL;
     449         [ #  # ]:          0 :         if (num_pos < 1)
     450                 :            :                 return 0;
     451                 :            : 
     452                 :          0 :         nrc = input_mt_set_matrix(mt, pos, num_pos, mu);
     453                 :          0 :         find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc, mu);
     454                 :          0 :         input_mt_set_slots(mt, slots, num_pos);
     455                 :            : 
     456                 :          0 :         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                 :          0 : int input_mt_get_slot_by_key(struct input_dev *dev, int key)
     473                 :            : {
     474                 :          0 :         struct input_mt *mt = dev->mt;
     475                 :          0 :         struct input_mt_slot *s;
     476                 :            : 
     477         [ #  # ]:          0 :         if (!mt)
     478                 :            :                 return -1;
     479                 :            : 
     480         [ #  # ]:          0 :         for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
     481   [ #  #  #  # ]:          0 :                 if (input_mt_is_active(s) && s->key == key)
     482                 :          0 :                         return s - mt->slots;
     483                 :            : 
     484         [ #  # ]:          0 :         for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
     485   [ #  #  #  # ]:          0 :                 if (!input_mt_is_active(s) && !input_mt_is_used(mt, s)) {
     486                 :          0 :                         s->key = key;
     487                 :          0 :                         return s - mt->slots;
     488                 :            :                 }
     489                 :            : 
     490                 :            :         return -1;
     491                 :            : }
     492                 :            : EXPORT_SYMBOL(input_mt_get_slot_by_key);

Generated by: LCOV version 1.14