diff options
author | Angela Czubak <acz@semihalf.com> | 2022-07-20 11:15:28 -0700 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2022-07-20 11:35:13 -0700 |
commit | ebfa0043c96c7c7f645d0f96159bca988c873b6d (patch) | |
tree | 3324cb5f82a20050a790bdb42f78438a4e50093b /drivers/input/input-mt.c | |
parent | 59b7a5af8e8c22b20fc68eca48d7cfdc92501c1e (diff) |
Input: deactivate MT slots when inhibiting or suspending devices
When inhibiting or suspending a device we are sending release events for
all currently held keys and buttons, however we retain active MT slot
state, which causes issues with gesture recognition when we resume or
uninhibit.
Let's fix it by introducing, in addition to input_dev_release_keys(),
nput_mt_release_slots() that will deactivate all currently active slots.
Signed-off-by: Angela Czubak <acz@semihalf.com>
Link: https://lore.kernel.org/r/20220718151715.1052842-3-acz@semihalf.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/input-mt.c')
-rw-r--r-- | drivers/input/input-mt.c | 48 |
1 files changed, 44 insertions, 4 deletions
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index 44fe6f2f063c..14b53dac1253 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c @@ -8,6 +8,7 @@ #include <linux/input/mt.h> #include <linux/export.h> #include <linux/slab.h> +#include "input-core-private.h" #define TRKID_SGN ((TRKID_MAX + 1) >> 1) @@ -259,10 +260,13 @@ static void __input_mt_drop_unused(struct input_dev *dev, struct input_mt *mt) { int i; + lockdep_assert_held(&dev->event_lock); + for (i = 0; i < mt->num_slots; i++) { - if (!input_mt_is_used(mt, &mt->slots[i])) { - input_mt_slot(dev, i); - input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); + if (input_mt_is_active(&mt->slots[i]) && + !input_mt_is_used(mt, &mt->slots[i])) { + input_handle_event(dev, EV_ABS, ABS_MT_SLOT, i); + input_handle_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); } } } @@ -278,13 +282,44 @@ void input_mt_drop_unused(struct input_dev *dev) struct input_mt *mt = dev->mt; if (mt) { + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + __input_mt_drop_unused(dev, mt); mt->frame++; + + spin_unlock_irqrestore(&dev->event_lock, flags); } } EXPORT_SYMBOL(input_mt_drop_unused); /** + * input_mt_release_slots() - Deactivate all slots + * @dev: input device with allocated MT slots + * + * Lift all active slots. + */ +void input_mt_release_slots(struct input_dev *dev) +{ + struct input_mt *mt = dev->mt; + + lockdep_assert_held(&dev->event_lock); + + if (mt) { + /* This will effectively mark all slots unused. */ + mt->frame++; + + __input_mt_drop_unused(dev, mt); + + if (test_bit(ABS_PRESSURE, dev->absbit)) + input_handle_event(dev, EV_ABS, ABS_PRESSURE, 0); + + mt->frame++; + } +} + +/** * input_mt_sync_frame() - synchronize mt frame * @dev: input device with allocated MT slots * @@ -300,8 +335,13 @@ void input_mt_sync_frame(struct input_dev *dev) if (!mt) return; - if (mt->flags & INPUT_MT_DROP_UNUSED) + if (mt->flags & INPUT_MT_DROP_UNUSED) { + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); __input_mt_drop_unused(dev, mt); + spin_unlock_irqrestore(&dev->event_lock, flags); + } if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT)) use_count = true; |