aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo Krummrich <danilokrummrich@dk-develop.de>2022-02-15 14:45:43 -0800
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2022-02-15 17:25:39 -0800
commit81b9fd6941ce6fc4b4127cc184e491adb615182e (patch)
treeb93652f1ba89efb64cf521007918b824eb939d3c
parentInput: ps2-gpio - remove tx timeout from ps2_gpio_irq_tx() (diff)
downloadlinux-dev-81b9fd6941ce6fc4b4127cc184e491adb615182e.tar.xz
linux-dev-81b9fd6941ce6fc4b4127cc184e491adb615182e.zip
Input: ps2-gpio - don't send rx data before the stop bit
Sending the data before processing the stop bit from the device already saves the data of the current xfer in case the stop bit is missed. However, when TX xfers are enabled this introduces a race condition when a peripheral driver using the bus immediately requests a TX xfer from IRQ context. Therefore the data must be send after receiving the stop bit, although it is possible the data is lost when missing the stop bit. Signed-off-by: Danilo Krummrich <danilokrummrich@dk-develop.de> Link: https://lore.kernel.org/r/20220215160208.34826-5-danilokrummrich@dk-develop.de Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--drivers/input/serio/ps2-gpio.c22
1 files changed, 8 insertions, 14 deletions
diff --git a/drivers/input/serio/ps2-gpio.c b/drivers/input/serio/ps2-gpio.c
index e471c0fec536..a1e5f3baa281 100644
--- a/drivers/input/serio/ps2-gpio.c
+++ b/drivers/input/serio/ps2-gpio.c
@@ -225,6 +225,13 @@ static irqreturn_t ps2_gpio_irq_rx(struct ps2_gpio_data *drvdata)
if (!drvdata->write_enable)
goto err;
}
+ break;
+ case PS2_STOP_BIT:
+ /* stop bit should be high */
+ if (unlikely(!data)) {
+ dev_err(drvdata->dev, "RX: stop bit should be high\n");
+ goto err;
+ }
/*
* Do not send spurious ACK's and NACK's when write fn is
@@ -237,22 +244,9 @@ static irqreturn_t ps2_gpio_irq_rx(struct ps2_gpio_data *drvdata)
break;
}
- /*
- * Let's send the data without waiting for the stop bit to be
- * sent. It may happen that we miss the stop bit. When this
- * happens we have no way to recover from this, certainly
- * missing the parity bit would be recognized when processing
- * the stop bit. When missing both, data is lost.
- */
serio_interrupt(drvdata->serio, byte, rxflags);
dev_dbg(drvdata->dev, "RX: sending byte 0x%x\n", byte);
- break;
- case PS2_STOP_BIT:
- /* stop bit should be high */
- if (unlikely(!data)) {
- dev_err(drvdata->dev, "RX: stop bit should be high\n");
- goto err;
- }
+
cnt = byte = 0;
goto end; /* success */