Skip to content

Commit fe8d561

Browse files
author
Benjamin Tissoires
committed
selftests/hid: add wq test for hid_bpf_input_report()
Now that bpf_wq is available, we can write a test with it. Having hid_bpf_input_report() waiting for the device means that we can directly call it, and we get that event when the device is ready. Link: https://patch.msgid.link/[email protected] Acked-by: Jiri Kosina <[email protected]> Signed-off-by: Benjamin Tissoires <[email protected]>
1 parent fa03f39 commit fe8d561

File tree

3 files changed

+126
-0
lines changed

3 files changed

+126
-0
lines changed

tools/testing/selftests/hid/hid_bpf.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,44 @@ TEST_F(hid_bpf, test_hid_infinite_loop_output_report_call)
11301130
err);
11311131
}
11321132

1133+
/*
1134+
* Attach hid_multiply_event_wq to the given uhid device,
1135+
* retrieve and open the matching hidraw node,
1136+
* inject one event in the uhid device,
1137+
* check that the program sees it and can add extra data
1138+
*/
1139+
TEST_F(hid_bpf, test_multiply_events_wq)
1140+
{
1141+
const struct test_program progs[] = {
1142+
{ .name = "hid_test_multiply_events_wq" },
1143+
};
1144+
__u8 buf[10] = {0};
1145+
int err;
1146+
1147+
LOAD_PROGRAMS(progs);
1148+
1149+
/* inject one event */
1150+
buf[0] = 1;
1151+
buf[1] = 42;
1152+
uhid_send_event(_metadata, self->uhid_fd, buf, 6);
1153+
1154+
/* read the data from hidraw */
1155+
memset(buf, 0, sizeof(buf));
1156+
err = read(self->hidraw_fd, buf, sizeof(buf));
1157+
ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
1158+
ASSERT_EQ(buf[0], 1);
1159+
ASSERT_EQ(buf[1], 47);
1160+
1161+
usleep(100000);
1162+
1163+
/* read the data from hidraw */
1164+
memset(buf, 0, sizeof(buf));
1165+
err = read(self->hidraw_fd, buf, sizeof(buf));
1166+
ASSERT_EQ(err, 9) TH_LOG("read_hidraw");
1167+
ASSERT_EQ(buf[0], 2);
1168+
ASSERT_EQ(buf[1], 3);
1169+
}
1170+
11331171
/*
11341172
* Attach hid_insert{0,1,2} to the given uhid device,
11351173
* retrieve and open the matching hidraw node,

tools/testing/selftests/hid/progs/hid.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,3 +443,82 @@ SEC(".struct_ops.link")
443443
struct hid_bpf_ops test_infinite_loop_output_report = {
444444
.hid_hw_output_report = (void *)hid_test_infinite_loop_output_report,
445445
};
446+
447+
struct elem {
448+
struct bpf_wq work;
449+
};
450+
451+
struct {
452+
__uint(type, BPF_MAP_TYPE_HASH);
453+
__uint(max_entries, 1);
454+
__type(key, int);
455+
__type(value, struct elem);
456+
} hmap SEC(".maps");
457+
458+
static int wq_cb_sleepable(void *map, int *key, struct bpf_wq *work)
459+
{
460+
__u8 buf[9] = {2, 3, 4, 5, 6, 7, 8, 9, 10};
461+
struct hid_bpf_ctx *hid_ctx;
462+
463+
hid_ctx = hid_bpf_allocate_context(*key);
464+
if (!hid_ctx)
465+
return 0; /* EPERM check */
466+
467+
hid_bpf_input_report(hid_ctx, HID_INPUT_REPORT, buf, sizeof(buf));
468+
469+
hid_bpf_release_context(hid_ctx);
470+
471+
return 0;
472+
}
473+
474+
static int test_inject_input_report_callback(int *key)
475+
{
476+
struct elem init = {}, *val;
477+
struct bpf_wq *wq;
478+
479+
if (bpf_map_update_elem(&hmap, key, &init, 0))
480+
return -1;
481+
482+
val = bpf_map_lookup_elem(&hmap, key);
483+
if (!val)
484+
return -2;
485+
486+
wq = &val->work;
487+
if (bpf_wq_init(wq, &hmap, 0) != 0)
488+
return -3;
489+
490+
if (bpf_wq_set_callback(wq, wq_cb_sleepable, 0))
491+
return -4;
492+
493+
if (bpf_wq_start(wq, 0))
494+
return -5;
495+
496+
return 0;
497+
}
498+
499+
SEC("?struct_ops/hid_device_event")
500+
int BPF_PROG(hid_test_multiply_events_wq, struct hid_bpf_ctx *hid_ctx, enum hid_report_type type)
501+
{
502+
__u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 9 /* size */);
503+
int hid = hid_ctx->hid->id;
504+
int ret;
505+
506+
if (!data)
507+
return 0; /* EPERM check */
508+
509+
if (data[0] != 1)
510+
return 0;
511+
512+
ret = test_inject_input_report_callback(&hid);
513+
if (ret)
514+
return ret;
515+
516+
data[1] += 5;
517+
518+
return 0;
519+
}
520+
521+
SEC(".struct_ops.link")
522+
struct hid_bpf_ops test_multiply_events_wq = {
523+
.hid_device_event = (void *)hid_test_multiply_events_wq,
524+
};

tools/testing/selftests/hid/progs/hid_bpf_helpers.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,13 @@ extern int hid_bpf_input_report(struct hid_bpf_ctx *ctx,
9090
__u8 *data,
9191
size_t buf__sz) __ksym;
9292

93+
/* bpf_wq implementation */
94+
extern int bpf_wq_init(struct bpf_wq *wq, void *p__map, unsigned int flags) __weak __ksym;
95+
extern int bpf_wq_start(struct bpf_wq *wq, unsigned int flags) __weak __ksym;
96+
extern int bpf_wq_set_callback_impl(struct bpf_wq *wq,
97+
int (callback_fn)(void *map, int *key, struct bpf_wq *wq),
98+
unsigned int flags__k, void *aux__ign) __ksym;
99+
#define bpf_wq_set_callback(timer, cb, flags) \
100+
bpf_wq_set_callback_impl(timer, cb, flags, NULL)
101+
93102
#endif /* __HID_BPF_HELPERS_H */

0 commit comments

Comments
 (0)