diff options
| author | Benjamin Tissoires <bentiss@kernel.org> | 2026-04-03 18:12:23 +0200 |
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.com> | 2026-04-08 21:46:00 +0200 |
| commit | bb8be68d1280eff1abb697136b54576af218b266 (patch) | |
| tree | 957ae60adba2d1b470af1d18c7125be87512cf0c | |
| parent | fc778f21a18e79cfb1ad17b7af0478e21ab41daf (diff) | |
hid: bpf: hid_bpf_helpers: add helper for having read/write udev properties
We want udev-hid-bpf to be able to set udev properties by printing them
out after the BPF object has been loaded. This allows to make a query to
the device, and set a udev prop based on the answer.
Because the way udev works, the properties are cleared on bind/unbind,
and we need a way to store them. After several attempts to keep the
property alive without re-running the udev-hid-bpf tool to communicate
with the device, it came out that HID-BPF maps are pinned in the bpffs
and we can then query them.
So the following would export a UDEV property in the bpffs:
EXPORT_UDEV_PROP(HID_FOO, 32);
SEC("syscall")
int probe(struct hid_bpf_probe_args *ctx)
{
const char *foo = "foo";
UDEV_PROP_SPRINTF(HID_FOO, "%s", foo);
return 0;
}
Then, we can debug it with a simple cat:
sudo cat /sys/fs/bpf/hid/.../UDEV_PROP_HID_FOO
0: {['f','o','o',],}
This way, the property is always accessible without talking to the
device
Link: https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/merge_requests/220
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
| -rw-r--r-- | drivers/hid/bpf/progs/hid_bpf_helpers.h | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/drivers/hid/bpf/progs/hid_bpf_helpers.h b/drivers/hid/bpf/progs/hid_bpf_helpers.h index c67facdefff3..0fd8e7d90742 100644 --- a/drivers/hid/bpf/progs/hid_bpf_helpers.h +++ b/drivers/hid/bpf/progs/hid_bpf_helpers.h @@ -340,6 +340,44 @@ DEFINE_GUARD(bpf_spin, struct bpf_spin_lock, bpf_spin_lock, bpf_spin_unlock); #define hid_bpf_cpu_to_be32(x) bpf_htonl(x) #define hid_bpf_cpu_to_be64(x) bpf_cpu_to_be64(x) +/* + * The following macros are helpers for exporting udev properties: + * + * EXPORT_UDEV_PROP(name, len) generates: + * - a map with a single element UDEV_PROP_##name, of size len + * - a const global declaration of that len: SIZEOF_##name + * + * udev_prop_ptr(name) retrieves the data pointer behind the map. + * + * UDEV_PROP_SPRINTF(name, fmt, ...) writes data into the udev property. + * + * Can be used as such: + * EXPORT_UDEV_PROP(HID_FOO, 32); + * + * SEC("syscall") + * int probe(struct hid_bpf_probe_args *ctx) + * { + * const char *foo = "foo"; + * UDEV_PROP_SPRINTF(HID_FOO, "%s", foo); + * + * return 0; + * } + */ +#define EXPORT_UDEV_PROP(name, len) \ + const __u32 SIZEOF_##name = len; \ + struct COMBINE(udev_prop, __LINE__) { \ + __uint(type, BPF_MAP_TYPE_ARRAY); \ + __uint(max_entries, 1); \ + __type(key, __u32); \ + __type(value, __u8[len]); \ + } UDEV_PROP_##name SEC(".maps"); + +#define udev_prop_ptr(name) \ + bpf_map_lookup_elem(&UDEV_PROP_##name, &(__u32){0}) + +#define UDEV_PROP_SPRINTF(name, fmt, ...) \ + BPF_SNPRINTF(udev_prop_ptr(name), SIZEOF_##name, fmt, ##__VA_ARGS__) + static inline __maybe_unused __u16 field_start_byte(struct hid_rdesc_field *field) { return field->bits_start / 8; |
