Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input - mt: Fix input_mt_get_slot_by_key

The case occurred recently with a touchscreen using twice a slot during a
single EV_SYN event:

E: 0.288415 0000 0000 0000 # ------------ SYN_REPORT (0) ----------
E: 0.296207 0003 002f 0000 # EV_ABS / ABS_MT_SLOT 0
E: 0.296207 0003 0039 -001 # EV_ABS / ABS_MT_TRACKING_ID -1
E: 0.296207 0003 002f 0001 # EV_ABS / ABS_MT_SLOT 1
E: 0.296207 0003 0035 0908 # EV_ABS / ABS_MT_POSITION_X 908
E: 0.296207 0003 0036 1062 # EV_ABS / ABS_MT_POSITION_Y 1062
E: 0.296207 0003 002f 0000 # EV_ABS / ABS_MT_SLOT 0
E: 0.296207 0003 0039 8787 # EV_ABS / ABS_MT_TRACKING_ID 8787
E: 0.296207 0003 0035 1566 # EV_ABS / ABS_MT_POSITION_X 1566
E: 0.296207 0003 0036 0861 # EV_ABS / ABS_MT_POSITION_Y 861
E: 0.296207 0003 0000 0908 # EV_ABS / ABS_X 908
E: 0.296207 0003 0001 1062 # EV_ABS / ABS_Y 1062
E: 0.296207 0000 0000 0000 # ------------ SYN_REPORT (0) ----------

This occurred because while having already slots 0 and 1 assigned, the
touchscreen sent:

0.293377 Tip Switch: 0 | Contact Id: 0 | X: 539 | Y: 1960 | Contact Count: 3
0.294783 Tip Switch: 1 | Contact Id: 1 | X: 908 | Y: 1062 | Contact Count: 0
0.296187 Tip Switch: 1 | Contact Id: 2 | X: 1566 | Y: 861 | Contact Count: 0

Slot 0 is released correclty, but when we look for Contact ID 2, the slot
0 is then picked up again because it is marked as inactive (trackingID < 0).

This is wrong, and we should not reuse a slot in the same frame.
The test should also check for input_mt_is_used().

In addition, we need to initialize mt->frame to an other value than 0.
With mt->frame being 0, all slots are tags as currently used, and so
input_mt_get_slot_by_key() would return -1 for all requests.

Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=88903

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

authored by

Benjamin Tissoires and committed by
Jiri Kosina
c6275892 b9e9cd32

+7 -2
+7 -2
drivers/input/input-mt.c
··· 88 88 goto err_mem; 89 89 } 90 90 91 - /* Mark slots as 'unused' */ 91 + /* Mark slots as 'inactive' */ 92 92 for (i = 0; i < num_slots; i++) 93 93 input_mt_set_value(&mt->slots[i], ABS_MT_TRACKING_ID, -1); 94 + 95 + /* Mark slots as 'unused' */ 96 + mt->frame = 1; 94 97 95 98 dev->mt = mt; 96 99 return 0; ··· 433 430 * set the key on the first unused slot and return. 434 431 * 435 432 * If no available slot can be found, -1 is returned. 433 + * Note that for this function to work properly, input_mt_sync_frame() has 434 + * to be called at each frame. 436 435 */ 437 436 int input_mt_get_slot_by_key(struct input_dev *dev, int key) 438 437 { ··· 449 444 return s - mt->slots; 450 445 451 446 for (s = mt->slots; s != mt->slots + mt->num_slots; s++) 452 - if (!input_mt_is_active(s)) { 447 + if (!input_mt_is_active(s) && !input_mt_is_used(mt, s)) { 453 448 s->key = key; 454 449 return s - mt->slots; 455 450 }