return __hid_bpf_attach_prog(hdev, prog_type, prog_fd, flags);
 }
 
+/**
+ * hid_bpf_allocate_context - Allocate a context to the given HID device
+ *
+ * @hid_id: the system unique identifier of the HID device
+ *
+ * @returns A pointer to &struct hid_bpf_ctx on success, %NULL on error.
+ */
+noinline struct hid_bpf_ctx *
+hid_bpf_allocate_context(unsigned int hid_id)
+{
+       struct hid_device *hdev;
+       struct hid_bpf_ctx_kern *ctx_kern = NULL;
+       struct device *dev;
+
+       if (!hid_bpf_ops)
+               return NULL;
+
+       dev = bus_find_device(hid_bpf_ops->bus_type, NULL, &hid_id, device_match_id);
+       if (!dev)
+               return NULL;
+
+       hdev = to_hid_device(dev);
+
+       ctx_kern = kzalloc(sizeof(*ctx_kern), GFP_KERNEL);
+       if (!ctx_kern)
+               return NULL;
+
+       ctx_kern->ctx.hid = hdev;
+
+       return &ctx_kern->ctx;
+}
+
+/**
+ * hid_bpf_release_context - Release the previously allocated context @ctx
+ *
+ * @ctx: the HID-BPF context to release
+ *
+ */
+noinline void
+hid_bpf_release_context(struct hid_bpf_ctx *ctx)
+{
+       struct hid_bpf_ctx_kern *ctx_kern;
+
+       if (!ctx)
+               return;
+
+       ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
+
+       kfree(ctx_kern);
+}
+
+/**
+ * hid_bpf_hw_request - Communicate with 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
+ * @rtype: the type of the report (%HID_INPUT_REPORT, %HID_FEATURE_REPORT, %HID_OUTPUT_REPORT)
+ * @reqtype: the type of the request (%HID_REQ_GET_REPORT, %HID_REQ_SET_REPORT, ...)
+ *
+ * @returns %0 on success, a negative error code otherwise.
+ */
+noinline int
+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;
+       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;
+       }
+
+       switch (reqtype) {
+       case HID_REQ_GET_REPORT:
+       case HID_REQ_GET_IDLE:
+       case HID_REQ_GET_PROTOCOL:
+       case HID_REQ_SET_REPORT:
+       case HID_REQ_SET_IDLE:
+       case HID_REQ_SET_PROTOCOL:
+               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;
+
+       dma_data = kmemdup(buf, buf__sz, GFP_KERNEL);
+       if (!dma_data)
+               return -ENOMEM;
+
+       ret = hid_bpf_ops->hid_hw_raw_request(hdev,
+                                             dma_data[0],
+                                             dma_data,
+                                             buf__sz,
+                                             rtype,
+                                             reqtype);
+
+       if (ret > 0)
+               memcpy(buf, dma_data, ret);
+
+       kfree(dma_data);
+       return ret;
+}
+
 /* for syscall HID-BPF */
 BTF_SET8_START(hid_bpf_syscall_kfunc_ids)
 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_SET8_END(hid_bpf_syscall_kfunc_ids)
 
 static const struct btf_kfunc_id_set hid_bpf_syscall_kfunc_set = {
 
 int hid_bpf_device_event(struct hid_bpf_ctx *ctx);
 
 /* Following functions are kfunc that we export to BPF programs */
-/* only available in tracing */
+/* available everywhere in HID-BPF */
 __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t __sz);
 
 /* only available in syscall */
 int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags);
+int 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_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id);
+void hid_bpf_release_context(struct hid_bpf_ctx *ctx);
 
 /*
  * Below is HID internal
        HID_BPF_PROG_TYPE_MAX,
 };
 
+struct hid_report_enum;
+
 struct hid_bpf_ops {
+       struct hid_report *(*hid_get_report)(struct hid_report_enum *report_enum, const u8 *data);
+       int (*hid_hw_raw_request)(struct hid_device *hdev,
+                                 unsigned char reportnum, __u8 *buf,
+                                 size_t len, enum hid_report_type rtype,
+                                 enum hid_class_request reqtype);
        struct module *owner;
        struct bus_type *bus_type;
 };