[PATCH 2/2] HID: bpf: rescan the device for the group after a load/unload

Benjamin Tissoires posted 2 patches 1 month, 1 week ago
[PATCH 2/2] HID: bpf: rescan the device for the group after a load/unload
Posted by Benjamin Tissoires 1 month, 1 week ago
When a BPF gets loaded, it was previously not possible to bind a
hid-generic device to hid-multitouch because the group was never
updated.

This change forces a rescan of the report descriptor after a bpf is
loaded/unloaded so we set up the proper group.

This was detected while Peter was trying to fix a Viewsonic device: the
HID device sending multiotuch data through a proprietary collection was
handled by hid-generic, and we don't have any way of attaching it to
hid-multitouch because the pre-scanning wasn't able to see the Contact
ID HID usage.

Suggested-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
---
 drivers/hid/hid-core.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index cf68fdffe0581eefb29a9d691f4acfc8f0d175d5..a5b3a8ca2fcbc868470dd50ec14e4c7829dd863b 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -943,6 +943,15 @@ static int hid_scan_report(struct hid_device *hid)
 	parser->device = hid;
 	hid->group = HID_GROUP_GENERIC;
 
+	/*
+	 * In case we are re-scanning after a BPF has been loaded,
+	 * we need to use the bpf report descriptor, not the original one.
+	 */
+	if (hid->bpf_rdesc && hid->bpf_rsize) {
+		start = hid->bpf_rdesc;
+		end = start + hid->bpf_rsize;
+	}
+
 	/*
 	 * The parsing is simpler than the one in hid_open_report() as we should
 	 * be robust against hid errors. Those errors will be raised by
@@ -2728,6 +2737,12 @@ static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv)
 	int ret;
 
 	if (!hdev->bpf_rsize) {
+		/* we keep a reference to the currently scanned report descriptor */
+		const __u8  *original_rdesc = hdev->bpf_rdesc;
+
+		if (!original_rdesc)
+			original_rdesc = hdev->dev_rdesc;
+
 		/* in case a bpf program gets detached, we need to free the old one */
 		hid_free_bpf_rdesc(hdev);
 
@@ -2737,6 +2752,12 @@ static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv)
 		/* call_hid_bpf_rdesc_fixup will always return a valid pointer */
 		hdev->bpf_rdesc = call_hid_bpf_rdesc_fixup(hdev, hdev->dev_rdesc,
 							   &hdev->bpf_rsize);
+
+		/* the report descriptor changed, we need to re-scan it */
+		if (original_rdesc != hdev->bpf_rdesc) {
+			hdev->group = 0;
+			hid_set_group(hdev);
+		}
 	}
 
 	if (!hid_check_device_match(hdev, hdrv, &id))

-- 
2.50.1