mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
HID: bpf: export hid_hw_output_report as a BPF kfunc
We currently only export hid_hw_raw_request() as a BPF kfunc. However, some devices require an explicit write on the Output Report instead of the use of the control channel. So also export hid_hw_output_report to BPF Link: https://lore.kernel.org/r/20240315-b4-hid-bpf-new-funcs-v4-2-079c282469d3@kernel.org Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
This commit is contained in:
parent
4171954f56
commit
5599f80196
@ -179,7 +179,7 @@ Available API that can be used in syscall HID-BPF programs:
|
||||
-----------------------------------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/hid/bpf/hid_bpf_dispatch.c
|
||||
:functions: hid_bpf_attach_prog hid_bpf_hw_request hid_bpf_allocate_context hid_bpf_release_context
|
||||
:functions: hid_bpf_attach_prog hid_bpf_hw_request hid_bpf_hw_output_report hid_bpf_allocate_context hid_bpf_release_context
|
||||
|
||||
General overview of a HID-BPF program
|
||||
=====================================
|
||||
|
@ -376,6 +376,46 @@ hid_bpf_release_context(struct hid_bpf_ctx *ctx)
|
||||
put_device(&hid->dev);
|
||||
}
|
||||
|
||||
static int
|
||||
__hid_bpf_hw_check_params(struct hid_bpf_ctx *ctx, __u8 *buf, size_t *buf__sz,
|
||||
enum hid_report_type rtype)
|
||||
{
|
||||
struct hid_report_enum *report_enum;
|
||||
struct hid_report *report;
|
||||
struct hid_device *hdev;
|
||||
u32 report_len;
|
||||
|
||||
/* check arguments */
|
||||
if (!ctx || !hid_bpf_ops || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
switch (rtype) {
|
||||
case HID_INPUT_REPORT:
|
||||
case HID_OUTPUT_REPORT:
|
||||
case HID_FEATURE_REPORT:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (*buf__sz < 1)
|
||||
return -EINVAL;
|
||||
|
||||
hdev = (struct hid_device *)ctx->hid; /* discard const */
|
||||
|
||||
report_enum = hdev->report_enum + rtype;
|
||||
report = hid_bpf_ops->hid_get_report(report_enum, buf);
|
||||
if (!report)
|
||||
return -EINVAL;
|
||||
|
||||
report_len = hid_report_len(report);
|
||||
|
||||
if (*buf__sz > report_len)
|
||||
*buf__sz = report_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hid_bpf_hw_request - Communicate with a HID device
|
||||
*
|
||||
@ -392,24 +432,14 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
|
||||
enum hid_report_type rtype, enum hid_class_request reqtype)
|
||||
{
|
||||
struct hid_device *hdev;
|
||||
struct hid_report *report;
|
||||
struct hid_report_enum *report_enum;
|
||||
size_t size = buf__sz;
|
||||
u8 *dma_data;
|
||||
u32 report_len;
|
||||
int ret;
|
||||
|
||||
/* check arguments */
|
||||
if (!ctx || !hid_bpf_ops || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
switch (rtype) {
|
||||
case HID_INPUT_REPORT:
|
||||
case HID_OUTPUT_REPORT:
|
||||
case HID_FEATURE_REPORT:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = __hid_bpf_hw_check_params(ctx, buf, &size, rtype);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (reqtype) {
|
||||
case HID_REQ_GET_REPORT:
|
||||
@ -423,29 +453,16 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (buf__sz < 1)
|
||||
return -EINVAL;
|
||||
|
||||
hdev = (struct hid_device *)ctx->hid; /* discard const */
|
||||
|
||||
report_enum = hdev->report_enum + rtype;
|
||||
report = hid_bpf_ops->hid_get_report(report_enum, buf);
|
||||
if (!report)
|
||||
return -EINVAL;
|
||||
|
||||
report_len = hid_report_len(report);
|
||||
|
||||
if (buf__sz > report_len)
|
||||
buf__sz = report_len;
|
||||
|
||||
dma_data = kmemdup(buf, buf__sz, GFP_KERNEL);
|
||||
dma_data = kmemdup(buf, size, GFP_KERNEL);
|
||||
if (!dma_data)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = hid_bpf_ops->hid_hw_raw_request(hdev,
|
||||
dma_data[0],
|
||||
dma_data,
|
||||
buf__sz,
|
||||
size,
|
||||
rtype,
|
||||
reqtype);
|
||||
|
||||
@ -455,6 +472,42 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
|
||||
kfree(dma_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* hid_bpf_hw_output_report - Send an output report to a HID device
|
||||
*
|
||||
* @ctx: the HID-BPF context previously allocated in hid_bpf_allocate_context()
|
||||
* @buf: a %PTR_TO_MEM buffer
|
||||
* @buf__sz: the size of the data to transfer
|
||||
*
|
||||
* Returns the number of bytes transferred on success, a negative error code otherwise.
|
||||
*/
|
||||
__bpf_kfunc int
|
||||
hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)
|
||||
{
|
||||
struct hid_device *hdev;
|
||||
size_t size = buf__sz;
|
||||
u8 *dma_data;
|
||||
int ret;
|
||||
|
||||
/* check arguments */
|
||||
ret = __hid_bpf_hw_check_params(ctx, buf, &size, HID_OUTPUT_REPORT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
hdev = (struct hid_device *)ctx->hid; /* discard const */
|
||||
|
||||
dma_data = kmemdup(buf, size, GFP_KERNEL);
|
||||
if (!dma_data)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = hid_bpf_ops->hid_hw_output_report(hdev,
|
||||
dma_data,
|
||||
size);
|
||||
|
||||
kfree(dma_data);
|
||||
return ret;
|
||||
}
|
||||
__bpf_kfunc_end_defs();
|
||||
|
||||
/*
|
||||
@ -488,6 +541,7 @@ BTF_ID_FLAGS(func, hid_bpf_attach_prog)
|
||||
BTF_ID_FLAGS(func, hid_bpf_allocate_context, KF_ACQUIRE | KF_RET_NULL)
|
||||
BTF_ID_FLAGS(func, hid_bpf_release_context, KF_RELEASE)
|
||||
BTF_ID_FLAGS(func, hid_bpf_hw_request)
|
||||
BTF_ID_FLAGS(func, hid_bpf_hw_output_report)
|
||||
BTF_KFUNCS_END(hid_bpf_syscall_kfunc_ids)
|
||||
|
||||
static const struct btf_kfunc_id_set hid_bpf_syscall_kfunc_set = {
|
||||
|
@ -2974,6 +2974,7 @@ EXPORT_SYMBOL_GPL(hid_check_keys_pressed);
|
||||
static struct hid_bpf_ops hid_ops = {
|
||||
.hid_get_report = hid_get_report,
|
||||
.hid_hw_raw_request = hid_hw_raw_request,
|
||||
.hid_hw_output_report = hid_hw_output_report,
|
||||
.owner = THIS_MODULE,
|
||||
.bus_type = &hid_bus_type,
|
||||
};
|
||||
|
@ -103,6 +103,7 @@ struct hid_bpf_ops {
|
||||
unsigned char reportnum, __u8 *buf,
|
||||
size_t len, enum hid_report_type rtype,
|
||||
enum hid_class_request reqtype);
|
||||
int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len);
|
||||
struct module *owner;
|
||||
const struct bus_type *bus_type;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user