[PATCH v2 3/5] Input: applespi - register touchpad synchronously in probe

From: Shih-Yuan Lee

Date: Mon Jul 20 2026 - 06:20:31 EST


Touchpad registration is currently deferred to an asynchronous worker
applespi_worker(). This asynchronous registration introduces race
conditions if debugfs or other properties are accessed before the worker
completes, or if the driver is unbound while the worker is active.

Remove the workqueue and the asynchronous worker. Perform touchpad
registration synchronously during driver probe.

Wait up to 3 seconds for the touchpad information command packet response
using wait_event_timeout(). If the response times out, log a warning and
fallback to keyboard-only mode. If registration fails, gracefully unwind GPE
handlers and wait for outstanding SPI transactions to complete.

To prevent data races between the interrupt handler and the probe thread,
protect the 'have_tp_info' flag and 'rcvd_tp_info' structure under the
cmd_msg_lock in applespi_handle_cmd_response().

Signed-off-by: Shih-Yuan Lee <fourdollars@xxxxxxxxxx>
---
drivers/input/keyboard/applespi.c | 52 +++++++++++++++++++++----------
1 file changed, 36 insertions(+), 16 deletions(-)

diff --git a/drivers/input/keyboard/applespi.c b/drivers/input/keyboard/applespi.c
index a8f8d5370e95..42b7f87ef2cd 100644
--- a/drivers/input/keyboard/applespi.c
+++ b/drivers/input/keyboard/applespi.c
@@ -427,7 +427,7 @@ struct applespi_data {
} spi_complete[2];
bool cancel_spi;

- struct work_struct work;
+ bool have_tp_info;
struct touchpad_info_protocol rcvd_tp_info;

struct dentry *debugfs_root;
@@ -1388,26 +1388,20 @@ applespi_register_touchpad_device(struct applespi_data *applespi,
return 0;
}

-static void applespi_worker(struct work_struct *work)
-{
- struct applespi_data *applespi =
- container_of(work, struct applespi_data, work);
-
- applespi_register_touchpad_device(applespi, &applespi->rcvd_tp_info);
-}
-
static void applespi_handle_cmd_response(struct applespi_data *applespi,
struct spi_packet *packet,
struct message *message)
{
+ unsigned long flags;
+
if (packet->device == PACKET_DEV_INFO &&
le16_to_cpu(message->type) == 0x1020) {
- /*
- * We're not allowed to sleep here, but registering an input
- * device can sleep.
- */
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
applespi->rcvd_tp_info = message->tp_info;
- schedule_work(&applespi->work);
+ applespi->have_tp_info = true;
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+
+ wake_up_all(&applespi->wait_queue);
return;
}

@@ -1675,6 +1669,7 @@ static int applespi_probe(struct spi_device *spi)
acpi_handle spi_handle = ACPI_HANDLE(&spi->dev);
acpi_status acpi_sts;
int sts, i;
+ unsigned long flags;
unsigned long long gpe, usb_status;

/* check if the USB interface is present and enabled already */
@@ -1692,8 +1687,6 @@ static int applespi_probe(struct spi_device *spi)

applespi->spi = spi;

- INIT_WORK(&applespi->work, applespi_worker);
-
/* store the driver data */
spi_set_drvdata(spi, applespi);

@@ -1821,6 +1814,20 @@ static int applespi_probe(struct spi_device *spi)
/* trigger touchpad setup */
applespi_init(applespi, false);

+ /* set up the touchpad as a separate input device if info is received */
+ sts = wait_event_timeout(applespi->wait_queue,
+ READ_ONCE(applespi->have_tp_info),
+ msecs_to_jiffies(3000));
+ if (!sts) {
+ dev_warn(&applespi->spi->dev,
+ "Timed out waiting for touchpad info, continuing keyboard-only\n");
+ } else {
+ sts = applespi_register_touchpad_device(applespi,
+ &applespi->rcvd_tp_info);
+ if (sts)
+ goto cancel_spi;
+ }
+
/*
* By default this device is not enabled for wakeup; but USB keyboards
* generally are, so the expectation is that by default the keyboard
@@ -1853,6 +1860,19 @@ static int applespi_probe(struct spi_device *spi)
&applespi_tp_dim_fops);

return 0;
+
+cancel_spi:
+ acpi_disable_gpe(NULL, applespi->gpe);
+ acpi_remove_gpe_handler(NULL, applespi->gpe, applespi_notify);
+
+ spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+ applespi->cancel_spi = true;
+ wait_event_lock_irq(applespi->wait_queue,
+ !applespi_async_outstanding(applespi),
+ applespi->cmd_msg_lock);
+ spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+
+ return sts;
}

static void applespi_drain_writes(struct applespi_data *applespi)
--
2.39.5