[PATCH 14/21] HID: pantherlord: move FF initialization to .input_configured()

Dmitry Torokhov <[email protected]>
Newsgroups org.kernel.vger.linux-kernel,org.kernel.vger.linux-doc,org.kernel.vger.linux-input
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-pl.c | 150 ++++++++++++++++++++++-----------------------------
 1 file changed, 65 insertions(+), 85 deletions(-)

diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c
index 8bba29ef6c7a..cae56a6c941b 100644
--- a/drivers/hid/hid-pl.c
+++ b/drivers/hid/hid-pl.c
@@ -62,15 +62,13 @@ static int hid_plff_play(struct input_dev *dev, void *data,
 	return 0;
 }
 
-static int plff_init(struct hid_device *hid)
+static int pl_input_configured(struct hid_device *hid, struct hid_input *hidinput)
 {
 	struct plff_device *plff;
 	struct hid_report *report;
-	struct hid_input *hidinput;
 	struct list_head *report_list =
 			&hid->report_enum[HID_OUTPUT_REPORT].report_list;
-	struct list_head *report_ptr = report_list;
-	struct input_dev *dev;
+	struct input_dev *dev = hidinput->input;
 	int error;
 	s32 maxval;
 	s32 *strong;
@@ -83,89 +81,80 @@ static int plff_init(struct hid_device *hid)
 	   The input reports also contain a field which contains
 	   8 ff00.0001 usages and 8 boolean values. Their meaning is
 	   currently unknown.
-	   
+
 	   A version of the 0e8f:0003 exists that has all the values in
 	   separate fields and misses the extra input field, thus resembling
 	   Zeroplus (hid-zpff) devices.
 	*/
 
-	if (list_empty(report_list)) {
+	if (!list_is_first(&hidinput->list, &hid->inputs))
+		return 0;
+
+	report = list_first_entry_or_null(report_list, struct hid_report, list);
+	if (!report) {
 		hid_err(hid, "no output reports found\n");
 		return -ENODEV;
 	}
+	if (report->maxfield < 1) {
+		hid_err(hid, "no fields in the report\n");
+		return -ENODEV;
+	}
 
-	list_for_each_entry(hidinput, &hid->inputs, list) {
-
-		report_ptr = report_ptr->next;
-
-		if (report_ptr == report_list) {
-			hid_err(hid, "required output report is missing\n");
-			return -ENODEV;
-		}
-
-		report = list_entry(report_ptr, struct hid_report, list);
-		if (report->maxfield < 1) {
-			hid_err(hid, "no fields in the report\n");
-			return -ENODEV;
-		}
-
-		maxval = 0x7f;
-		if (report->field[0]->report_count >= 4) {
-			report->field[0]->value[0] = 0x00;
-			report->field[0]->value[1] = 0x00;
-			strong = &report->field[0]->value[2];
-			weak = &report->field[0]->value[3];
-			hid_dbg(hid, "detected single-field device");
-		} else if (report->field[0]->maxusage == 1 &&
-			   report->field[0]->usage[0].hid ==
-				(HID_UP_LED | 0x43) &&
-			   report->maxfield >= 4 &&
-			   report->field[0]->report_count >= 1 &&
-			   report->field[1]->report_count >= 1 &&
-			   report->field[2]->report_count >= 1 &&
-			   report->field[3]->report_count >= 1) {
-			report->field[0]->value[0] = 0x00;
-			report->field[1]->value[0] = 0x00;
-			strong = &report->field[2]->value[0];
-			weak = &report->field[3]->value[0];
-			if (hid->vendor == USB_VENDOR_ID_JESS2)
-				maxval = 0xff;
-			hid_dbg(hid, "detected 4-field device");
-		} else {
-			hid_err(hid, "not enough fields or values\n");
-			return -ENODEV;
-		}
-
-		plff = kzalloc_obj(struct plff_device);
-		if (!plff)
-			return -ENOMEM;
-
-		dev = hidinput->input;
-
-		set_bit(FF_RUMBLE, dev->ffbit);
-
-		error = input_ff_create_memless(dev, plff, hid_plff_play);
-		if (error) {
-			kfree(plff);
-			return error;
-		}
-
-		plff->report = report;
-		plff->strong = strong;
-		plff->weak = weak;
-		plff->maxval = maxval;
-
-		*strong = 0x00;
-		*weak = 0x00;
-		hid_hw_request(hid, plff->report, HID_REQ_SET_REPORT);
+	maxval = 0x7f;
+	if (report->field[0]->report_count >= 4) {
+		report->field[0]->value[0] = 0x00;
+		report->field[0]->value[1] = 0x00;
+		strong = &report->field[0]->value[2];
+		weak = &report->field[0]->value[3];
+		hid_dbg(hid, "detected single-field device");
+	} else if (report->field[0]->maxusage == 1 &&
+		   report->field[0]->usage[0].hid ==
+			(HID_UP_LED | 0x43) &&
+		   report->maxfield >= 4 &&
+		   report->field[0]->report_count >= 1 &&
+		   report->field[1]->report_count >= 1 &&
+		   report->field[2]->report_count >= 1 &&
+		   report->field[3]->report_count >= 1) {
+		report->field[0]->value[0] = 0x00;
+		report->field[1]->value[0] = 0x00;
+		strong = &report->field[2]->value[0];
+		weak = &report->field[3]->value[0];
+		if (hid->vendor == USB_VENDOR_ID_JESS2)
+			maxval = 0xff;
+		hid_dbg(hid, "detected 4-field device");
+	} else {
+		hid_err(hid, "not enough fields or values\n");
+		return -ENODEV;
 	}
 
-	hid_info(hid, "Force feedback for PantherLord/GreenAsia devices by Anssi Hannula <[email protected]>\n");
+	plff = kzalloc_obj(struct plff_device);
+	if (!plff)
+		return -ENOMEM;
+
+	dev = hidinput->input;
+
+	set_bit(FF_RUMBLE, dev->ffbit);
+
+	error = input_ff_create_memless(dev, plff, hid_plff_play);
+	if (error) {
+		kfree(plff);
+		return error;
+	}
+
+	plff->report = report;
+	plff->strong = strong;
+	plff->weak = weak;
+	plff->maxval = maxval;
+
+	*strong = 0x00;
+	*weak = 0x00;
+	hid_hw_request(hid, plff->report, HID_REQ_SET_REPORT);
 
 	return 0;
 }
 #else
-static inline int plff_init(struct hid_device *hid)
+static inline int pl_input_configured(struct hid_device *hid,
+				      struct hid_input *hidinput)
 {
 	return 0;
 }
@@ -181,27 +170,17 @@ static int pl_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;
+		return ret;
 	}
 
-	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 	if (ret) {
 		hid_err(hdev, "hw start failed\n");
-		goto err;
+		return ret;
 	}
 
-	ret = plff_init(hdev);
-	if (ret)
-		goto stop;
-
 	return 0;
-
-stop:
-	hid_hw_stop(hdev);
-err:
-	return ret;
 }
-
 static const struct hid_device_id pl_devices[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR),
 		.driver_data = 1 }, /* Twin USB Joystick */
@@ -217,6 +196,7 @@ static struct hid_driver pl_driver = {
 	.name = "pantherlord",
 	.id_table = pl_devices,
 	.probe = pl_probe,
+	.input_configured = pl_input_configured,
 };
 module_hid_driver(pl_driver);
 

-- 
2.55.0.629.g250fe7f194-goog
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.