When we are in a user_event context, we can talk to the device to fetch or set features/outputs/inputs reports. Add a bpf helper to do so. This helper is thus only available to user_events, because calling this function while in IRQ context (any other BPF type) is forbidden.
Signed-off-by: Benjamin Tissoires benjamin.tissoires@redhat.com
---
changes in v2: - split the series by bpf/libbpf/hid/selftests and samples --- include/linux/bpf-hid.h | 2 ++ include/uapi/linux/bpf.h | 8 ++++++++ kernel/bpf/hid.c | 26 ++++++++++++++++++++++++++ tools/include/uapi/linux/bpf.h | 8 ++++++++ 4 files changed, 44 insertions(+)
diff --git a/include/linux/bpf-hid.h b/include/linux/bpf-hid.h index 4cf2e99109fe..bd548f6a4a26 100644 --- a/include/linux/bpf-hid.h +++ b/include/linux/bpf-hid.h @@ -100,6 +100,8 @@ struct bpf_hid_hooks { u64 offset, u32 n, u8 *data, u64 data_size); int (*hid_set_data)(struct hid_device *hdev, u8 *buf, size_t buf_size, u64 offset, u32 n, u8 *data, u64 data_size); + int (*hid_raw_request)(struct hid_device *hdev, u8 *buf, size_t size, + u8 rtype, u8 reqtype); };
#ifdef CONFIG_BPF diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index b3063384d380..417cf1c31579 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -5121,6 +5121,13 @@ union bpf_attr { * Return * The length of data copied into ctx->event.data. On error, a negative * value is returned. + * + * int bpf_hid_raw_request(void *ctx, void *buf, u64 size, u8 rtype, u8 reqtype) + * Description + * communicate with the HID device + * Return + * 0 on success. + * negative value on error. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5317,6 +5324,7 @@ union bpf_attr { FN(copy_from_user_task), \ FN(hid_get_data), \ FN(hid_set_data), \ + FN(hid_raw_request), \ /* */
/* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/kernel/bpf/hid.c b/kernel/bpf/hid.c index de003dbd7d01..653d10c0f4e6 100644 --- a/kernel/bpf/hid.c +++ b/kernel/bpf/hid.c @@ -86,6 +86,28 @@ static const struct bpf_func_proto bpf_hid_set_data_proto = { .arg5_type = ARG_CONST_SIZE_OR_ZERO, };
+BPF_CALL_5(bpf_hid_raw_request, void*, ctx, void*, buf, u64, size, + u8, rtype, u8, reqtype) +{ + struct hid_bpf_ctx *bpf_ctx = ctx; + + if (!hid_hooks.hid_raw_request) + return -EOPNOTSUPP; + + return hid_hooks.hid_raw_request(bpf_ctx->hdev, buf, size, rtype, reqtype); +} + +static const struct bpf_func_proto bpf_hid_raw_request_proto = { + .func = bpf_hid_raw_request, + .gpl_only = true, /* hid_raw_request is EXPORT_SYMBOL_GPL */ + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_PTR_TO_MEM, + .arg3_type = ARG_CONST_SIZE_OR_ZERO, + .arg4_type = ARG_ANYTHING, + .arg5_type = ARG_ANYTHING, +}; + static const struct bpf_func_proto * hid_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { @@ -94,6 +116,10 @@ hid_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_hid_get_data_proto; case BPF_FUNC_hid_set_data: return &bpf_hid_set_data_proto; + case BPF_FUNC_hid_raw_request: + if (prog->expected_attach_type != BPF_HID_DEVICE_EVENT) + return &bpf_hid_raw_request_proto; + return NULL; default: return bpf_base_func_proto(func_id); } diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index b3063384d380..417cf1c31579 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -5121,6 +5121,13 @@ union bpf_attr { * Return * The length of data copied into ctx->event.data. On error, a negative * value is returned. + * + * int bpf_hid_raw_request(void *ctx, void *buf, u64 size, u8 rtype, u8 reqtype) + * Description + * communicate with the HID device + * Return + * 0 on success. + * negative value on error. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -5317,6 +5324,7 @@ union bpf_attr { FN(copy_from_user_task), \ FN(hid_get_data), \ FN(hid_set_data), \ + FN(hid_raw_request), \ /* */
/* integer value in 'imm' field of BPF_CALL instruction selects which helper