Commit e52cd628 authored by David Jander's avatar David Jander Committed by Dmitry Torokhov

Input: ads7846 - fix race that causes missing releases

If touchscreen is released while busy reading HWMON device, the release
can be missed. The IRQ thread is not started because no touch is active
and BTN_TOUCH release event is never sent.

Fixes: f5a28a7d ("Input: ads7846 - avoid pen up/down when reading hwmon")
Co-developed-by: default avatarOleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: default avatarDavid Jander <david@protonic.nl>
Signed-off-by: default avatarOleksij Rempel <o.rempel@pengutronix.de>
Link: https://lore.kernel.org/r/20201027105416.18773-1-o.rempel@pengutronix.deSigned-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent cd536aa5
......@@ -199,6 +199,26 @@ struct ads7846 {
#define REF_ON (READ_12BIT_DFR(x, 1, 1))
#define REF_OFF (READ_12BIT_DFR(y, 0, 0))
static int get_pendown_state(struct ads7846 *ts)
{
if (ts->get_pendown_state)
return ts->get_pendown_state();
return !gpio_get_value(ts->gpio_pendown);
}
static void ads7846_report_pen_up(struct ads7846 *ts)
{
struct input_dev *input = ts->input;
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_PRESSURE, 0);
input_sync(input);
ts->pendown = false;
dev_vdbg(&ts->spi->dev, "UP\n");
}
/* Must be called with ts->lock held */
static void ads7846_stop(struct ads7846 *ts)
{
......@@ -215,6 +235,10 @@ static void ads7846_stop(struct ads7846 *ts)
static void ads7846_restart(struct ads7846 *ts)
{
if (!ts->disabled && !ts->suspended) {
/* Check if pen was released since last stop */
if (ts->pendown && !get_pendown_state(ts))
ads7846_report_pen_up(ts);
/* Tell IRQ thread that it may poll the device. */
ts->stopped = false;
mb();
......@@ -606,14 +630,6 @@ static const struct attribute_group ads784x_attr_group = {
/*--------------------------------------------------------------------------*/
static int get_pendown_state(struct ads7846 *ts)
{
if (ts->get_pendown_state)
return ts->get_pendown_state();
return !gpio_get_value(ts->gpio_pendown);
}
static void null_wait_for_sync(void)
{
}
......@@ -868,16 +884,8 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
msecs_to_jiffies(TS_POLL_PERIOD));
}
if (ts->pendown && !ts->stopped) {
struct input_dev *input = ts->input;
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_PRESSURE, 0);
input_sync(input);
ts->pendown = false;
dev_vdbg(&ts->spi->dev, "UP\n");
}
if (ts->pendown && !ts->stopped)
ads7846_report_pen_up(ts);
return IRQ_HANDLED;
}
......
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