HID: bpf: rescan the device for the group after a load/unload

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>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
This commit is contained in:
Benjamin Tissoires
2025-08-21 16:38:14 +02:00
committed by Jiri Kosina
parent 4e411a3f7b
commit 4c2c5ff9f3

View File

@@ -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))