LCOV - code coverage report
Current view: top level - drivers/input - input-mt.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 168 0.0 %
Date: 2014-02-18 Functions: 0 13 0.0 %
Branches: 0 142 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Input Multitouch Library
       3                 :            :  *
       4                 :            :  * Copyright (c) 2008-2010 Henrik Rydberg
       5                 :            :  *
       6                 :            :  * This program is free software; you can redistribute it and/or modify it
       7                 :            :  * under the terms of the GNU General Public License version 2 as published by
       8                 :            :  * the Free Software Foundation.
       9                 :            :  */
      10                 :            : 
      11                 :            : #include <linux/input/mt.h>
      12                 :            : #include <linux/export.h>
      13                 :            : #include <linux/slab.h>
      14                 :            : 
      15                 :            : #define TRKID_SGN       ((TRKID_MAX + 1) >> 1)
      16                 :            : 
      17                 :          0 : static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src)
      18                 :            : {
      19 [ #  # ][ #  # ]:          0 :         if (dev->absinfo && test_bit(src, dev->absbit)) {
      20                 :          0 :                 dev->absinfo[dst] = dev->absinfo[src];
      21                 :          0 :                 dev->absinfo[dst].fuzz = 0;
      22                 :          0 :                 dev->absbit[BIT_WORD(dst)] |= BIT_MASK(dst);
      23                 :            :         }
      24                 :          0 : }
      25                 :            : 
      26                 :            : /**
      27                 :            :  * input_mt_init_slots() - initialize MT input slots
      28                 :            :  * @dev: input device supporting MT events and finger tracking
      29                 :            :  * @num_slots: number of slots used by the device
      30                 :            :  * @flags: mt tasks to handle in core
      31                 :            :  *
      32                 :            :  * This function allocates all necessary memory for MT slot handling
      33                 :            :  * in the input device, prepares the ABS_MT_SLOT and
      34                 :            :  * ABS_MT_TRACKING_ID events for use and sets up appropriate buffers.
      35                 :            :  * Depending on the flags set, it also performs pointer emulation and
      36                 :            :  * frame synchronization.
      37                 :            :  *
      38                 :            :  * May be called repeatedly. Returns -EINVAL if attempting to
      39                 :            :  * reinitialize with a different number of slots.
      40                 :            :  */
      41                 :          0 : int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
      42                 :            :                         unsigned int flags)
      43                 :            : {
      44                 :          0 :         struct input_mt *mt = dev->mt;
      45                 :            :         int i;
      46                 :            : 
      47         [ #  # ]:          0 :         if (!num_slots)
      48                 :            :                 return 0;
      49         [ #  # ]:          0 :         if (mt)
      50         [ #  # ]:          0 :                 return mt->num_slots != num_slots ? -EINVAL : 0;
      51                 :            : 
      52                 :          0 :         mt = kzalloc(sizeof(*mt) + num_slots * sizeof(*mt->slots), GFP_KERNEL);
      53         [ #  # ]:          0 :         if (!mt)
      54                 :            :                 goto err_mem;
      55                 :            : 
      56                 :          0 :         mt->num_slots = num_slots;
      57                 :          0 :         mt->flags = flags;
      58                 :          0 :         input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
      59                 :          0 :         input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
      60                 :            : 
      61         [ #  # ]:          0 :         if (flags & (INPUT_MT_POINTER | INPUT_MT_DIRECT)) {
      62                 :            :                 __set_bit(EV_KEY, dev->evbit);
      63                 :            :                 __set_bit(BTN_TOUCH, dev->keybit);
      64                 :            : 
      65                 :          0 :                 copy_abs(dev, ABS_X, ABS_MT_POSITION_X);
      66                 :          0 :                 copy_abs(dev, ABS_Y, ABS_MT_POSITION_Y);
      67                 :          0 :                 copy_abs(dev, ABS_PRESSURE, ABS_MT_PRESSURE);
      68                 :            :         }
      69         [ #  # ]:          0 :         if (flags & INPUT_MT_POINTER) {
      70                 :            :                 __set_bit(BTN_TOOL_FINGER, dev->keybit);
      71                 :            :                 __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
      72         [ #  # ]:          0 :                 if (num_slots >= 3)
      73                 :            :                         __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
      74         [ #  # ]:          0 :                 if (num_slots >= 4)
      75                 :            :                         __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
      76         [ #  # ]:          0 :                 if (num_slots >= 5)
      77                 :            :                         __set_bit(BTN_TOOL_QUINTTAP, dev->keybit);
      78                 :            :                 __set_bit(INPUT_PROP_POINTER, dev->propbit);
      79                 :            :         }
      80         [ #  # ]:          0 :         if (flags & INPUT_MT_DIRECT)
      81                 :            :                 __set_bit(INPUT_PROP_DIRECT, dev->propbit);
      82         [ #  # ]:          0 :         if (flags & INPUT_MT_SEMI_MT)
      83                 :            :                 __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
      84         [ #  # ]:          0 :         if (flags & INPUT_MT_TRACK) {
      85                 :          0 :                 unsigned int n2 = num_slots * num_slots;
      86                 :          0 :                 mt->red = kcalloc(n2, sizeof(*mt->red), GFP_KERNEL);
      87         [ #  # ]:          0 :                 if (!mt->red)
      88                 :            :                         goto err_mem;
      89                 :            :         }
      90                 :            : 
      91                 :            :         /* Mark slots as 'unused' */
      92         [ #  # ]:          0 :         for (i = 0; i < num_slots; i++)
      93                 :          0 :                 input_mt_set_value(&mt->slots[i], ABS_MT_TRACKING_ID, -1);
      94                 :            : 
      95                 :          0 :         dev->mt = mt;
      96                 :          0 :         return 0;
      97                 :            : 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                 :          0 : void input_mt_destroy_slots(struct input_dev *dev)
     111                 :            : {
     112         [ #  # ]:          0 :         if (dev->mt) {
     113                 :          0 :                 kfree(dev->mt->red);
     114                 :          0 :                 kfree(dev->mt);
     115                 :            :         }
     116                 :          0 :         dev->mt = NULL;
     117                 :          0 : }
     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                 :          0 : void input_mt_report_slot_state(struct input_dev *dev,
     133                 :            :                                 unsigned int tool_type, bool active)
     134                 :            : {
     135                 :          0 :         struct input_mt *mt = dev->mt;
     136                 :            :         struct input_mt_slot *slot;
     137                 :            :         int id;
     138                 :            : 
     139         [ #  # ]:          0 :         if (!mt)
     140                 :            :                 return;
     141                 :            : 
     142                 :          0 :         slot = &mt->slots[mt->slot];
     143                 :          0 :         slot->frame = mt->frame;
     144                 :            : 
     145         [ #  # ]:          0 :         if (!active) {
     146                 :          0 :                 input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
     147                 :          0 :                 return;
     148                 :            :         }
     149                 :            : 
     150                 :            :         id = input_mt_get_value(slot, ABS_MT_TRACKING_ID);
     151 [ #  # ][ #  # ]:          0 :         if (id < 0 || input_mt_get_value(slot, ABS_MT_TOOL_TYPE) != tool_type)
     152                 :            :                 id = input_mt_new_trkid(mt);
     153                 :            : 
     154                 :          0 :         input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
     155                 :          0 :         input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);
     156                 :            : }
     157                 :            : EXPORT_SYMBOL(input_mt_report_slot_state);
     158                 :            : 
     159                 :            : /**
     160                 :            :  * input_mt_report_finger_count() - report contact count
     161                 :            :  * @dev: input device with allocated MT slots
     162                 :            :  * @count: the number of contacts
     163                 :            :  *
     164                 :            :  * Reports the contact count via BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP,
     165                 :            :  * BTN_TOOL_TRIPLETAP and BTN_TOOL_QUADTAP.
     166                 :            :  *
     167                 :            :  * The input core ensures only the KEY events already setup for
     168                 :            :  * this device will produce output.
     169                 :            :  */
     170                 :          0 : void input_mt_report_finger_count(struct input_dev *dev, int count)
     171                 :            : {
     172                 :          0 :         input_event(dev, EV_KEY, BTN_TOOL_FINGER, count == 1);
     173                 :          0 :         input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2);
     174                 :          0 :         input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3);
     175                 :          0 :         input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count == 4);
     176                 :          0 :         input_event(dev, EV_KEY, BTN_TOOL_QUINTTAP, count == 5);
     177                 :          0 : }
     178                 :            : EXPORT_SYMBOL(input_mt_report_finger_count);
     179                 :            : 
     180                 :            : /**
     181                 :            :  * input_mt_report_pointer_emulation() - common pointer emulation
     182                 :            :  * @dev: input device with allocated MT slots
     183                 :            :  * @use_count: report number of active contacts as finger count
     184                 :            :  *
     185                 :            :  * Performs legacy pointer emulation via BTN_TOUCH, ABS_X, ABS_Y and
     186                 :            :  * ABS_PRESSURE. Touchpad finger count is emulated if use_count is true.
     187                 :            :  *
     188                 :            :  * The input core ensures only the KEY and ABS axes already setup for
     189                 :            :  * this device will produce output.
     190                 :            :  */
     191                 :          0 : void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
     192                 :            : {
     193                 :          0 :         struct input_mt *mt = dev->mt;
     194                 :            :         struct input_mt_slot *oldest;
     195                 :            :         int oldid, count, i;
     196                 :            : 
     197         [ #  # ]:          0 :         if (!mt)
     198                 :          0 :                 return;
     199                 :            : 
     200                 :            :         oldest = NULL;
     201                 :          0 :         oldid = mt->trkid;
     202                 :            :         count = 0;
     203                 :            : 
     204         [ #  # ]:          0 :         for (i = 0; i < mt->num_slots; ++i) {
     205                 :          0 :                 struct input_mt_slot *ps = &mt->slots[i];
     206                 :            :                 int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
     207                 :            : 
     208         [ #  # ]:          0 :                 if (id < 0)
     209                 :          0 :                         continue;
     210         [ #  # ]:          0 :                 if ((id - oldid) & TRKID_SGN) {
     211                 :            :                         oldest = ps;
     212                 :            :                         oldid = id;
     213                 :            :                 }
     214                 :          0 :                 count++;
     215                 :            :         }
     216                 :            : 
     217                 :          0 :         input_event(dev, EV_KEY, BTN_TOUCH, count > 0);
     218         [ #  # ]:          0 :         if (use_count)
     219                 :          0 :                 input_mt_report_finger_count(dev, count);
     220                 :            : 
     221         [ #  # ]:          0 :         if (oldest) {
     222                 :            :                 int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
     223                 :            :                 int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);
     224                 :            : 
     225                 :          0 :                 input_event(dev, EV_ABS, ABS_X, x);
     226                 :          0 :                 input_event(dev, EV_ABS, ABS_Y, y);
     227                 :            : 
     228         [ #  # ]:          0 :                 if (test_bit(ABS_MT_PRESSURE, dev->absbit)) {
     229                 :            :                         int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
     230                 :          0 :                         input_event(dev, EV_ABS, ABS_PRESSURE, p);
     231                 :            :                 }
     232                 :            :         } else {
     233         [ #  # ]:          0 :                 if (test_bit(ABS_MT_PRESSURE, dev->absbit))
     234                 :          0 :                         input_event(dev, EV_ABS, ABS_PRESSURE, 0);
     235                 :            :         }
     236                 :            : }
     237                 :            : EXPORT_SYMBOL(input_mt_report_pointer_emulation);
     238                 :            : 
     239                 :            : /**
     240                 :            :  * input_mt_sync_frame() - synchronize mt frame
     241                 :            :  * @dev: input device with allocated MT slots
     242                 :            :  *
     243                 :            :  * Close the frame and prepare the internal state for a new one.
     244                 :            :  * Depending on the flags, marks unused slots as inactive and performs
     245                 :            :  * pointer emulation.
     246                 :            :  */
     247                 :          0 : void input_mt_sync_frame(struct input_dev *dev)
     248                 :            : {
     249                 :          0 :         struct input_mt *mt = dev->mt;
     250                 :          0 :         struct input_mt_slot *s;
     251                 :            :         bool use_count = false;
     252                 :            : 
     253         [ #  # ]:          0 :         if (!mt)
     254                 :          0 :                 return;
     255                 :            : 
     256         [ #  # ]:          0 :         if (mt->flags & INPUT_MT_DROP_UNUSED) {
     257         [ #  # ]:          0 :                 for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
     258         [ #  # ]:          0 :                         if (input_mt_is_used(mt, s))
     259                 :          0 :                                 continue;
     260                 :          0 :                         input_mt_slot(dev, s - mt->slots);
     261                 :          0 :                         input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
     262                 :            :                 }
     263                 :            :         }
     264                 :            : 
     265         [ #  # ]:          0 :         if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT))
     266                 :            :                 use_count = true;
     267                 :            : 
     268                 :          0 :         input_mt_report_pointer_emulation(dev, use_count);
     269                 :            : 
     270                 :          0 :         mt->frame++;
     271                 :            : }
     272                 :            : EXPORT_SYMBOL(input_mt_sync_frame);
     273                 :            : 
     274                 :          0 : static int adjust_dual(int *begin, int step, int *end, int eq)
     275                 :            : {
     276                 :            :         int f, *p, s, c;
     277                 :            : 
     278         [ #  # ]:          0 :         if (begin == end)
     279                 :            :                 return 0;
     280                 :            : 
     281                 :          0 :         f = *begin;
     282                 :          0 :         p = begin + step;
     283         [ #  # ]:          0 :         s = p == end ? f + 1 : *p;
     284                 :            : 
     285         [ #  # ]:          0 :         for (; p != end; p += step)
     286         [ #  # ]:          0 :                 if (*p < f)
     287                 :            :                         s = f, f = *p;
     288         [ #  # ]:          0 :                 else if (*p < s)
     289                 :            :                         s = *p;
     290                 :            : 
     291                 :          0 :         c = (f + s + 1) / 2;
     292 [ #  # ][ #  # ]:          0 :         if (c == 0 || (c > 0 && !eq))
     293                 :            :                 return 0;
     294         [ #  # ]:          0 :         if (s < 0)
     295                 :          0 :                 c *= 2;
     296                 :            : 
     297         [ #  # ]:          0 :         for (p = begin; p != end; p += step)
     298                 :          0 :                 *p -= c;
     299                 :            : 
     300 [ #  # ][ #  # ]:          0 :         return (c < s && s <= 0) || (f >= 0 && f < c);
     301                 :            : }
     302                 :            : 
     303                 :          0 : static void find_reduced_matrix(int *w, int nr, int nc, int nrc)
     304                 :            : {
     305                 :            :         int i, k, sum;
     306                 :            : 
     307         [ #  # ]:          0 :         for (k = 0; k < nrc; k++) {
     308         [ #  # ]:          0 :                 for (i = 0; i < nr; i++)
     309                 :          0 :                         adjust_dual(w + i, nr, w + i + nrc, nr <= nc);
     310                 :            :                 sum = 0;
     311         [ #  # ]:          0 :                 for (i = 0; i < nrc; i += nr)
     312                 :          0 :                         sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr);
     313         [ #  # ]:          0 :                 if (!sum)
     314                 :            :                         break;
     315                 :            :         }
     316                 :          0 : }
     317                 :            : 
     318                 :          0 : static int input_mt_set_matrix(struct input_mt *mt,
     319                 :            :                                const struct input_mt_pos *pos, int num_pos)
     320                 :            : {
     321                 :            :         const struct input_mt_pos *p;
     322                 :          0 :         struct input_mt_slot *s;
     323                 :          0 :         int *w = mt->red;
     324                 :            :         int x, y;
     325                 :            : 
     326         [ #  # ]:          0 :         for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
     327         [ #  # ]:          0 :                 if (!input_mt_is_active(s))
     328                 :          0 :                         continue;
     329                 :            :                 x = input_mt_get_value(s, ABS_MT_POSITION_X);
     330                 :            :                 y = input_mt_get_value(s, ABS_MT_POSITION_Y);
     331         [ #  # ]:          0 :                 for (p = pos; p != pos + num_pos; p++) {
     332                 :          0 :                         int dx = x - p->x, dy = y - p->y;
     333                 :          0 :                         *w++ = dx * dx + dy * dy;
     334                 :            :                 }
     335                 :            :         }
     336                 :            : 
     337                 :          0 :         return w - mt->red;
     338                 :            : }
     339                 :            : 
     340                 :          0 : static void input_mt_set_slots(struct input_mt *mt,
     341                 :            :                                int *slots, int num_pos)
     342                 :            : {
     343                 :          0 :         struct input_mt_slot *s;
     344                 :          0 :         int *w = mt->red, *p;
     345                 :            : 
     346         [ #  # ]:          0 :         for (p = slots; p != slots + num_pos; p++)
     347                 :          0 :                 *p = -1;
     348                 :            : 
     349         [ #  # ]:          0 :         for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
     350         [ #  # ]:          0 :                 if (!input_mt_is_active(s))
     351                 :          0 :                         continue;
     352         [ #  # ]:          0 :                 for (p = slots; p != slots + num_pos; p++)
     353         [ #  # ]:          0 :                         if (*w++ < 0)
     354                 :          0 :                                 *p = s - mt->slots;
     355                 :            :         }
     356                 :            : 
     357         [ #  # ]:          0 :         for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
     358         [ #  # ]:          0 :                 if (input_mt_is_active(s))
     359                 :          0 :                         continue;
     360         [ #  # ]:          0 :                 for (p = slots; p != slots + num_pos; p++)
     361         [ #  # ]:          0 :                         if (*p < 0) {
     362                 :          0 :                                 *p = s - mt->slots;
     363                 :          0 :                                 break;
     364                 :            :                         }
     365                 :            :         }
     366                 :          0 : }
     367                 :            : 
     368                 :            : /**
     369                 :            :  * input_mt_assign_slots() - perform a best-match assignment
     370                 :            :  * @dev: input device with allocated MT slots
     371                 :            :  * @slots: the slot assignment to be filled
     372                 :            :  * @pos: the position array to match
     373                 :            :  * @num_pos: number of positions
     374                 :            :  *
     375                 :            :  * Performs a best match against the current contacts and returns
     376                 :            :  * the slot assignment list. New contacts are assigned to unused
     377                 :            :  * slots.
     378                 :            :  *
     379                 :            :  * Returns zero on success, or negative error in case of failure.
     380                 :            :  */
     381                 :          0 : int input_mt_assign_slots(struct input_dev *dev, int *slots,
     382                 :            :                           const struct input_mt_pos *pos, int num_pos)
     383                 :            : {
     384                 :          0 :         struct input_mt *mt = dev->mt;
     385                 :            :         int nrc;
     386                 :            : 
     387 [ #  # ][ #  # ]:          0 :         if (!mt || !mt->red)
     388                 :            :                 return -ENXIO;
     389         [ #  # ]:          0 :         if (num_pos > mt->num_slots)
     390                 :            :                 return -EINVAL;
     391         [ #  # ]:          0 :         if (num_pos < 1)
     392                 :            :                 return 0;
     393                 :            : 
     394                 :          0 :         nrc = input_mt_set_matrix(mt, pos, num_pos);
     395                 :          0 :         find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc);
     396                 :          0 :         input_mt_set_slots(mt, slots, num_pos);
     397                 :            : 
     398                 :          0 :         return 0;
     399                 :            : }
     400                 :            : EXPORT_SYMBOL(input_mt_assign_slots);
     401                 :            : 
     402                 :            : /**
     403                 :            :  * input_mt_get_slot_by_key() - return slot matching key
     404                 :            :  * @dev: input device with allocated MT slots
     405                 :            :  * @key: the key of the sought slot
     406                 :            :  *
     407                 :            :  * Returns the slot of the given key, if it exists, otherwise
     408                 :            :  * set the key on the first unused slot and return.
     409                 :            :  *
     410                 :            :  * If no available slot can be found, -1 is returned.
     411                 :            :  */
     412                 :          0 : int input_mt_get_slot_by_key(struct input_dev *dev, int key)
     413                 :            : {
     414                 :          0 :         struct input_mt *mt = dev->mt;
     415                 :          0 :         struct input_mt_slot *s;
     416                 :            : 
     417         [ #  # ]:          0 :         if (!mt)
     418                 :            :                 return -1;
     419                 :            : 
     420         [ #  # ]:          0 :         for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
     421 [ #  # ][ #  # ]:          0 :                 if (input_mt_is_active(s) && s->key == key)
     422                 :          0 :                         return s - mt->slots;
     423                 :            : 
     424         [ #  # ]:          0 :         for (s = mt->slots; s != mt->slots + mt->num_slots; s++)
     425         [ #  # ]:          0 :                 if (!input_mt_is_active(s)) {
     426                 :          0 :                         s->key = key;
     427                 :          0 :                         return s - mt->slots;
     428                 :            :                 }
     429                 :            : 
     430                 :            :         return -1;
     431                 :            : }
     432                 :            : EXPORT_SYMBOL(input_mt_get_slot_by_key);

Generated by: LCOV version 1.9