[PATCH 12/21] HID: move generic FF initialization into hidinput_connect()
Dmitry Torokhov <[email protected]> Mon, 03 Aug 2026 11:46:37 -0700
| Newsgroups | org.kernel.vger.linux-input,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Generic force-feedback initialization (pidff) currently happens in hid_connect() after hidinput_connect() has already registered the input devices. This is racy as the device is live and visible to userspace before FF support is fully set up. Move the call to hdev->ff_init() into hidinput_connect(), ensuring it runs before input_register_device() is called. This closes the race window for standard PID-capable devices. The initialization now also checks (connect_mask & HID_CONNECT_FF) and !hid_has_ff_input() to avoid conflicts with custom FF implementations and respect driver opt-outs. Assisted-by: Gemini:gemini-3.1-pro Signed-off-by: Dmitry Torokhov <[email protected]> --- drivers/hid/hid-core.c | 21 ++------------------- drivers/hid/hid-input.c | 21 +++++++++++++++++++-- include/linux/hid.h | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 2767a171eae9..d8cba852d2b5 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2287,18 +2287,6 @@ static const BIN_ATTR_RO(report_descriptor, HID_MAX_DESCRIPTOR_SIZE); static const DEVICE_ATTR_RO(country); -static bool hid_has_ff_input(struct hid_device *hdev) -{ - struct hid_input *hidinput; - - list_for_each_entry(hidinput, &hdev->inputs, list) { - if (test_bit(EV_FF, hidinput->input->evbit)) - return true; - } - - return false; -} - int hid_connect(struct hid_device *hdev, unsigned int connect_mask) { static const char *types[] = { "Device", "Pointer", "Mouse", "Device", @@ -2324,8 +2312,8 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) if (hid_hiddev(hdev)) connect_mask |= HID_CONNECT_HIDDEV_FORCE; - if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev, - connect_mask & HID_CONNECT_HIDINPUT_FORCE)) + if ((connect_mask & HID_CONNECT_HIDINPUT) && + !hidinput_connect(hdev, connect_mask)) hdev->claimed |= HID_CLAIMED_INPUT; if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect && @@ -2347,11 +2335,6 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) hid_process_ordering(hdev); - if ((hdev->claimed & HID_CLAIMED_INPUT) && - (connect_mask & HID_CONNECT_FF) && hdev->ff_init && - !hid_has_ff_input(hdev)) - hdev->ff_init(hdev); - len = 0; if (hdev->claimed & HID_CLAIMED_INPUT) len += sprintf(buf + len, "input"); diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 3487600cadb4..70ec1b7e7d38 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -2317,7 +2317,19 @@ static inline void hidinput_configure_usages(struct hid_input *hidinput, * Read all reports and initialize the absolute field values. */ -int hidinput_connect(struct hid_device *hid, unsigned int force) +static bool hid_has_ff_input(struct hid_device *hdev) +{ + struct hid_input *hidinput; + + list_for_each_entry(hidinput, &hdev->inputs, list) { + if (test_bit(EV_FF, hidinput->input->evbit)) + return true; + } + + return false; +} + +int hidinput_connect(struct hid_device *hid, unsigned int connect_mask) { struct hid_driver *drv = hid->driver; struct hid_report *report; @@ -2330,7 +2342,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) hid->status &= ~HID_STAT_DUP_DETECTED; - if (!force) { + if (!(connect_mask & HID_CONNECT_HIDINPUT_FORCE)) { for (i = 0; i < hid->maxcollection; i++) { struct hid_collection *col = &hid->collection[i]; if (col->type == HID_COLLECTION_APPLICATION || @@ -2396,6 +2408,11 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) continue; } + if (list_is_first(&hidinput->list, &hid->inputs) && + (connect_mask & HID_CONNECT_FF) && hid->ff_init && + !hid_has_ff_input(hid)) + hid->ff_init(hid); + if (input_register_device(hidinput->input)) goto out_unwind; hidinput->registered = true; diff --git a/include/linux/hid.h b/include/linux/hid.h index b240baa95ab5..451c3e05d167 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -1021,7 +1021,7 @@ extern void hid_unregister_driver(struct hid_driver *); extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report); -extern int hidinput_connect(struct hid_device *hid, unsigned int force); +extern int hidinput_connect(struct hid_device *hid, unsigned int connect_mask); extern void hidinput_disconnect(struct hid_device *); void hidinput_reset_resume(struct hid_device *hid); -- 2.55.0.629.g250fe7f194-goog