drivers/input/mouse/cyapa.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-)
cyapa_enable_irq_for_cmd()/cyapa_disable_irq_for_cmd() and
cyapa_reinitialize call input_device_enabled() without holding
input->mutex. However, input_device_enabled() has
lockdep_assert_held(&dev->mutex).
Add mutex_lock()/mutex_unlock() around the input_device_enabled()
call to properly protect access to the input device state.
Signed-off-by: Ziyi Guo <n7l8m4@u.northwestern.edu>
---
drivers/input/mouse/cyapa.c | 27 ++++++++++++++++++++++++---
1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
index 00c87c0532a6..e5fe3b8b6548 100644
--- a/drivers/input/mouse/cyapa.c
+++ b/drivers/input/mouse/cyapa.c
@@ -525,8 +525,15 @@ static int cyapa_create_input_dev(struct cyapa *cyapa)
static void cyapa_enable_irq_for_cmd(struct cyapa *cyapa)
{
struct input_dev *input = cyapa->input;
+ bool input_enabled = false;
- if (!input || !input_device_enabled(input)) {
+ if (input) {
+ mutex_lock(&input->mutex);
+ input_enabled = input_device_enabled(input);
+ mutex_unlock(&input->mutex);
+ }
+
+ if (!input || !input_enabled) {
/*
* When input is NULL, TP must be in deep sleep mode.
* In this mode, later non-power I2C command will always failed
@@ -545,8 +552,15 @@ static void cyapa_enable_irq_for_cmd(struct cyapa *cyapa)
static void cyapa_disable_irq_for_cmd(struct cyapa *cyapa)
{
struct input_dev *input = cyapa->input;
+ bool input_enabled = false;
+
+ if (input) {
+ mutex_lock(&input->mutex);
+ input_enabled = input_device_enabled(input);
+ mutex_unlock(&input->mutex);
+ }
- if (!input || !input_device_enabled(input)) {
+ if (!input || !input_enabled) {
if (cyapa->gen >= CYAPA_GEN5)
disable_irq(cyapa->client->irq);
if (!input || cyapa->operational)
@@ -628,6 +642,7 @@ static int cyapa_reinitialize(struct cyapa *cyapa)
{
struct device *dev = &cyapa->client->dev;
struct input_dev *input = cyapa->input;
+ bool input_enabled = false;
int error;
if (pm_runtime_enabled(dev))
@@ -652,7 +667,13 @@ static int cyapa_reinitialize(struct cyapa *cyapa)
}
out:
- if (!input || !input_device_enabled(input)) {
+ if (input) {
+ mutex_lock(&input->mutex);
+ input_enabled = input_device_enabled(input);
+ mutex_unlock(&input->mutex);
+ }
+
+ if (!input || !input_enabled) {
/* Reset to power OFF state to save power when no user open. */
if (cyapa->operational)
cyapa->ops->set_power_mode(cyapa,
--
2.34.1
Hi Ziyi,
On Mon, Feb 02, 2026 at 10:02:23PM +0000, Ziyi Guo wrote:
> cyapa_enable_irq_for_cmd()/cyapa_disable_irq_for_cmd() and
> cyapa_reinitialize call input_device_enabled() without holding
> input->mutex. However, input_device_enabled() has
> lockdep_assert_held(&dev->mutex).
>
> Add mutex_lock()/mutex_unlock() around the input_device_enabled()
> call to properly protect access to the input device state.
>
> Signed-off-by: Ziyi Guo <n7l8m4@u.northwestern.edu>
> ---
> drivers/input/mouse/cyapa.c | 27 ++++++++++++++++++++++++---
> 1 file changed, 24 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
> index 00c87c0532a6..e5fe3b8b6548 100644
> --- a/drivers/input/mouse/cyapa.c
> +++ b/drivers/input/mouse/cyapa.c
> @@ -525,8 +525,15 @@ static int cyapa_create_input_dev(struct cyapa *cyapa)
> static void cyapa_enable_irq_for_cmd(struct cyapa *cyapa)
> {
> struct input_dev *input = cyapa->input;
> + bool input_enabled = false;
>
> - if (!input || !input_device_enabled(input)) {
> + if (input) {
> + mutex_lock(&input->mutex);
> + input_enabled = input_device_enabled(input);
> + mutex_unlock(&input->mutex);
This solves absolutely nothing. The value of input_enabled becomes stale
the very moment you release the mutex.
The driver requires much more through conversion to handle potential
races with opening and closing the input device.
Thanks.
--
Dmitry
On Tue, Feb 3, 2026 at 3:52 AM Dmitry Torokhov <dmitry.torokhov@gmail.com> wrote: > > The driver requires much more through conversion to handle potential > races with opening and closing the input device. > > Thanks. > > -- > Dmitry Hi Dmitry, Thank you for your time and comments. How about we go with an alternative approach, add a bool input_opened field to struct cyapa, set it in cyapa_open() and clear it in cyapa_close(), then replace input_device_enabled(input) with cyapa->input_opened. I guess this work because - The input core calls dev->open() exactly when input_device_enabled() transitions to true (first user open, uninhibit with users), and dev->close() exactly when it transitions to false (last user close, inhibit with users). So the flag mirrors input_device_enabled(). - cyapa_open() and cyapa_close() both hold state_sync_lock when setting the flag. All callers of cyapa_enable_irq_for_cmd(), cyapa_disable_irq_for_cmd(), and cyapa_reinitialize() that can reach the flag also hold state_sync_lock, so the check and the subsequent action (power mode change, IRQ enable/disable) are atomic, no TOCTOU window. Thank you again!
© 2016 - 2026 Red Hat, Inc.