Commit ebfa0043 authored by Angela Czubak's avatar Angela Czubak Committed by Dmitry Torokhov

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: default avatarAngela Czubak <acz@semihalf.com>
Link: https://lore.kernel.org/r/20220718151715.1052842-3-acz@semihalf.comSigned-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent 59b7a5af
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _INPUT_CORE_PRIVATE_H
#define _INPUT_CORE_PRIVATE_H
/*
* Functions and definitions that are private to input core,
* should not be used by input drivers or handlers.
*/
struct input_dev;
void input_mt_release_slots(struct input_dev *dev);
void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value);
#endif /* _INPUT_CORE_PRIVATE_H */
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/input/mt.h> #include <linux/input/mt.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "input-core-private.h"
#define TRKID_SGN ((TRKID_MAX + 1) >> 1) #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) ...@@ -259,10 +260,13 @@ static void __input_mt_drop_unused(struct input_dev *dev, struct input_mt *mt)
{ {
int i; int i;
lockdep_assert_held(&dev->event_lock);
for (i = 0; i < mt->num_slots; i++) { for (i = 0; i < mt->num_slots; i++) {
if (!input_mt_is_used(mt, &mt->slots[i])) { if (input_mt_is_active(&mt->slots[i]) &&
input_mt_slot(dev, i); !input_mt_is_used(mt, &mt->slots[i])) {
input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); input_handle_event(dev, EV_ABS, ABS_MT_SLOT, i);
input_handle_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
} }
} }
} }
...@@ -278,12 +282,43 @@ void input_mt_drop_unused(struct input_dev *dev) ...@@ -278,12 +282,43 @@ void input_mt_drop_unused(struct input_dev *dev)
struct input_mt *mt = dev->mt; struct input_mt *mt = dev->mt;
if (mt) { if (mt) {
unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags);
__input_mt_drop_unused(dev, mt); __input_mt_drop_unused(dev, mt);
mt->frame++; mt->frame++;
spin_unlock_irqrestore(&dev->event_lock, flags);
} }
} }
EXPORT_SYMBOL(input_mt_drop_unused); 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 * input_mt_sync_frame() - synchronize mt frame
* @dev: input device with allocated MT slots * @dev: input device with allocated MT slots
...@@ -300,8 +335,13 @@ void input_mt_sync_frame(struct input_dev *dev) ...@@ -300,8 +335,13 @@ void input_mt_sync_frame(struct input_dev *dev)
if (!mt) if (!mt)
return; 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); __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)) if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT))
use_count = true; use_count = true;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include "input-compat.h" #include "input-compat.h"
#include "input-core-private.h"
#include "input-poller.h" #include "input-poller.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
...@@ -142,6 +143,8 @@ static void input_pass_values(struct input_dev *dev, ...@@ -142,6 +143,8 @@ static void input_pass_values(struct input_dev *dev,
struct input_handle *handle; struct input_handle *handle;
struct input_value *v; struct input_value *v;
lockdep_assert_held(&dev->event_lock);
if (!count) if (!count)
return; return;
...@@ -384,8 +387,8 @@ static void input_event_dispose(struct input_dev *dev, int disposition, ...@@ -384,8 +387,8 @@ static void input_event_dispose(struct input_dev *dev, int disposition,
} }
} }
static void input_handle_event(struct input_dev *dev, void input_handle_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value) unsigned int type, unsigned int code, int value)
{ {
int disposition; int disposition;
...@@ -722,20 +725,21 @@ EXPORT_SYMBOL(input_close_device); ...@@ -722,20 +725,21 @@ EXPORT_SYMBOL(input_close_device);
* Simulate keyup events for all keys that are marked as pressed. * Simulate keyup events for all keys that are marked as pressed.
* The function must be called with dev->event_lock held. * The function must be called with dev->event_lock held.
*/ */
static void input_dev_release_keys(struct input_dev *dev) static bool input_dev_release_keys(struct input_dev *dev)
{ {
bool need_sync = false; bool need_sync = false;
int code; int code;
lockdep_assert_held(&dev->event_lock);
if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) { if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
for_each_set_bit(code, dev->key, KEY_CNT) { for_each_set_bit(code, dev->key, KEY_CNT) {
input_handle_event(dev, EV_KEY, code, 0); input_handle_event(dev, EV_KEY, code, 0);
need_sync = true; need_sync = true;
} }
if (need_sync)
input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
} }
return need_sync;
} }
/* /*
...@@ -762,7 +766,8 @@ static void input_disconnect_device(struct input_dev *dev) ...@@ -762,7 +766,8 @@ static void input_disconnect_device(struct input_dev *dev)
* generate events even after we done here but they will not * generate events even after we done here but they will not
* reach any handlers. * reach any handlers.
*/ */
input_dev_release_keys(dev); if (input_dev_release_keys(dev))
input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
list_for_each_entry(handle, &dev->h_list, d_node) list_for_each_entry(handle, &dev->h_list, d_node)
handle->open = 0; handle->open = 0;
...@@ -1757,7 +1762,8 @@ void input_reset_device(struct input_dev *dev) ...@@ -1757,7 +1762,8 @@ void input_reset_device(struct input_dev *dev)
spin_lock_irqsave(&dev->event_lock, flags); spin_lock_irqsave(&dev->event_lock, flags);
input_dev_toggle(dev, true); input_dev_toggle(dev, true);
input_dev_release_keys(dev); if (input_dev_release_keys(dev))
input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
spin_unlock_irqrestore(&dev->event_lock, flags); spin_unlock_irqrestore(&dev->event_lock, flags);
mutex_unlock(&dev->mutex); mutex_unlock(&dev->mutex);
...@@ -1779,7 +1785,9 @@ static int input_inhibit_device(struct input_dev *dev) ...@@ -1779,7 +1785,9 @@ static int input_inhibit_device(struct input_dev *dev)
} }
spin_lock_irq(&dev->event_lock); spin_lock_irq(&dev->event_lock);
input_mt_release_slots(dev);
input_dev_release_keys(dev); input_dev_release_keys(dev);
input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
input_dev_toggle(dev, false); input_dev_toggle(dev, false);
spin_unlock_irq(&dev->event_lock); spin_unlock_irq(&dev->event_lock);
...@@ -1830,7 +1838,8 @@ static int input_dev_suspend(struct device *dev) ...@@ -1830,7 +1838,8 @@ static int input_dev_suspend(struct device *dev)
* Keys that are pressed now are unlikely to be * Keys that are pressed now are unlikely to be
* still pressed when we resume. * still pressed when we resume.
*/ */
input_dev_release_keys(input_dev); if (input_dev_release_keys(input_dev))
input_handle_event(input_dev, EV_SYN, SYN_REPORT, 1);
/* Turn off LEDs and sounds, if any are active. */ /* Turn off LEDs and sounds, if any are active. */
input_dev_toggle(input_dev, false); input_dev_toggle(input_dev, false);
...@@ -1864,7 +1873,8 @@ static int input_dev_freeze(struct device *dev) ...@@ -1864,7 +1873,8 @@ static int input_dev_freeze(struct device *dev)
* Keys that are pressed now are unlikely to be * Keys that are pressed now are unlikely to be
* still pressed when we resume. * still pressed when we resume.
*/ */
input_dev_release_keys(input_dev); if (input_dev_release_keys(input_dev))
input_handle_event(input_dev, EV_SYN, SYN_REPORT, 1);
spin_unlock_irq(&input_dev->event_lock); spin_unlock_irq(&input_dev->event_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment