[PATCH 13/21] HID: microsoft: move FF initialization to .input_configured()

Dmitry Torokhov <[email protected]> Mon, 03 Aug 2026 11:46:38 -0700
Newsgroups org.kernel.vger.linux-input,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
The driver currently initializes force-feedback in its probe() function
after calling hid_hw_start(). This is racy as the input device is
already registered and visible to userspace at that point.

Move the FF initialization to the .input_configured() callback to ensure
the device is fully prepared before registration.

Assisted-by: Gemini:gemini-3.1-pro
Signed-off-by: Dmitry Torokhov <[email protected]>
---
 drivers/hid/hid-microsoft.c | 38 ++++++++------------------------------
 1 file changed, 8 insertions(+), 30 deletions(-)

diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index 18ac21c0bcb2..a7d3493a6141 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -323,22 +323,17 @@ static int ms_play_effect(struct input_dev *dev, void *data,
 	return 0;
 }
 
-static int ms_init_ff(struct hid_device *hdev)
+static int ms_input_configured(struct hid_device *hdev, struct hid_input *hidinput)
 {
-	struct hid_input *hidinput;
-	struct input_dev *input_dev;
 	struct ms_data *ms = hid_get_drvdata(hdev);
-
-	if (list_empty(&hdev->inputs)) {
-		hid_err(hdev, "no inputs found\n");
-		return -ENODEV;
-	}
-	hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
-	input_dev = hidinput->input;
+	struct input_dev *input_dev = hidinput->input;
 
 	if (!(ms->quirks & MS_QUIRK_FF))
 		return 0;
 
+	if (!list_is_first(&hidinput->list, &hdev->inputs))
+		return 0;
+
 	ms->hdev = hdev;
 	INIT_WORK(&ms->ff_worker, ms_ff_worker);
 
@@ -352,16 +347,6 @@ static int ms_init_ff(struct hid_device *hdev)
 	return input_ff_create_memless(input_dev, NULL, ms_play_effect);
 }
 
-static void ms_remove_ff(struct hid_device *hdev)
-{
-	struct ms_data *ms = hid_get_drvdata(hdev);
-
-	if (!(ms->quirks & MS_QUIRK_FF))
-		return;
-
-	cancel_work_sync(&ms->ff_worker);
-}
-
 static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
 	unsigned long quirks = id->driver_data;
@@ -385,29 +370,21 @@ static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id)
 	ret = hid_parse(hdev);
 	if (ret) {
 		hid_err(hdev, "parse failed\n");
-		goto err_free;
+		return ret;
 	}
 
 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | ((quirks & MS_HIDINPUT) ?
 				HID_CONNECT_HIDINPUT_FORCE : 0));
 	if (ret) {
 		hid_err(hdev, "hw start failed\n");
-		goto err_free;
+		return ret;
 	}
 
-	ret = ms_init_ff(hdev);
-	if (ret)
-		hid_err(hdev, "could not initialize ff, continuing anyway");
-
 	return 0;
-err_free:
-	return ret;
 }
-
 static void ms_remove(struct hid_device *hdev)
 {
 	hid_hw_stop(hdev);
-	ms_remove_ff(hdev);
 }
 
 static const struct hid_device_id ms_devices[] = {
@@ -469,6 +446,7 @@ static struct hid_driver ms_driver = {
 	.report_fixup = ms_report_fixup,
 	.input_mapping = ms_input_mapping,
 	.input_mapped = ms_input_mapped,
+	.input_configured = ms_input_configured,
 	.event = ms_event,
 	.probe = ms_probe,
 	.remove = ms_remove,

-- 
2.55.0.629.g250fe7f194-goog