@@ -54,11 +54,41 @@ FIXTURE_TEARDOWN(hid_bpf) {
hid_bpf_teardown(_metadata, self, variant); \
} while (0)
+struct specific_device {
+ const char test_name[64];
+ __u16 bus;
+ __u32 vid;
+ __u32 pid;
+};
+
FIXTURE_SETUP(hid_bpf)
{
+ const struct specific_device *match = NULL;
int err;
- err = setup_uhid(_metadata, &self->hid, BUS_USB, 0x0001, 0x0a36, rdesc, sizeof(rdesc));
+ const struct specific_device devices[] = {
+ {
+ .test_name = "test_hid_driver_probe",
+ .bus = BUS_BLUETOOTH,
+ .vid = 0x05ac, /* USB_VENDOR_ID_APPLE */
+ .pid = 0x022c, /* USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI */
+ }, {
+ .test_name = "*",
+ .bus = BUS_USB,
+ .vid = 0x0001,
+ .pid = 0x0a36,
+ }};
+
+ for (int i = 0; i < ARRAY_SIZE(devices); i++) {
+ match = &devices[i];
+ if (!strncmp(_metadata->name, devices[i].test_name, sizeof(devices[i].test_name)))
+ break;
+ }
+
+ ASSERT_OK_PTR(match);
+
+ err = setup_uhid(_metadata, &self->hid, match->bus, match->vid, match->pid,
+ rdesc, sizeof(rdesc));
ASSERT_OK(err);
}
@@ -855,6 +885,54 @@ TEST_F(hid_bpf, test_hid_attach_flags)
ASSERT_EQ(buf[3], 3);
}
+static bool is_using_driver(struct __test_metadata *_metadata, struct uhid_device *hid,
+ const char *driver)
+{
+ char driver_line[512];
+ char uevent[1024];
+ char temp[512];
+ int fd, nread;
+ bool found = false;
+
+ sprintf(uevent, "/sys/bus/hid/devices/%04X:%04X:%04X.%04X/uevent",
+ hid->bus, hid->vid, hid->pid, hid->hid_id);
+
+ fd = open(uevent, O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ TH_LOG("couldn't open '%s': %d, %d", uevent, fd, errno);
+ return false;
+ }
+
+ sprintf(driver_line, "DRIVER=%s", driver);
+
+ nread = read(fd, temp, ARRAY_SIZE(temp));
+ if (nread > 0 && (strstr(temp, driver_line)) != NULL)
+ found = true;
+
+ close(fd);
+
+ return found;
+}
+
+/*
+ * Attach hid_driver_probe to the given uhid device,
+ * check that the device is now using hid-generic.
+ */
+TEST_F(hid_bpf, test_hid_driver_probe)
+{
+ const struct test_program progs[] = {
+ {
+ .name = "hid_test_driver_probe",
+ },
+ };
+
+ ASSERT_TRUE(is_using_driver(_metadata, &self->hid, "apple"));
+
+ LOAD_PROGRAMS(progs);
+
+ ASSERT_TRUE(is_using_driver(_metadata, &self->hid, "hid-generic"));
+}
+
/*
* Attach hid_rdesc_fixup to the given uhid device,
* retrieve and open the matching hidraw node,
@@ -598,3 +598,32 @@ SEC(".struct_ops.link")
struct hid_bpf_ops test_infinite_loop_input_report = {
.hid_device_event = (void *)hid_test_infinite_loop_input_report,
};
+
+SEC("?struct_ops/hid_driver_probe")
+void BPF_PROG(hid_test_driver_probe, struct hid_device *hdev, struct hid_bpf_driver *hdrv,
+ struct hid_device_id *id)
+{
+ static const char hid_generic[] = "hid-generic";
+
+ bpf_printk("test_driver_probe, %s", hdrv->name);
+ if (!__builtin_memcmp(hdrv->name, hid_generic, sizeof(hid_generic)))
+ hdrv->force_driver = 1;
+ else
+ hdrv->ignore_driver = 1;
+}
+
+SEC("?struct_ops.s/hid_rdesc_fixup")
+int BPF_PROG(hid_rdesc_fixup_2, struct hid_bpf_ctx *hid_ctx)
+{
+ /*
+ * We need an empty report descriptor fixup to force detach/reattach
+ * the device when we load the BPF program.
+ */
+ return 0;
+}
+
+SEC(".struct_ops.link")
+struct hid_bpf_ops test_driver_probe = {
+ .hid_driver_probe = (void *)hid_test_driver_probe,
+ .hid_rdesc_fixup = (void *)hid_rdesc_fixup_2,
+};
@@ -81,6 +81,8 @@ struct hid_bpf_ops {
enum hid_report_type rtype, enum hid_class_request reqtype,
u64 source);
int (*hid_hw_output_report)(struct hid_bpf_ctx *ctx, u64 source);
+ void (*hid_driver_probe)(struct hid_device *hdev, struct hid_bpf_driver *hdrv,
+ struct hid_device_id *id);
struct hid_device *hdev;
};
We use a well known VID/PID on a driver that doesn't need to talk to the device, ensures we created the device against the target driver, then load our program and ensure we have unbound to this driver and use hid-generic instead. Signed-off-by: Benjamin Tissoires <bentiss@kernel.org> --- tools/testing/selftests/hid/hid_bpf.c | 80 +++++++++++++++++++++- tools/testing/selftests/hid/progs/hid.c | 29 ++++++++ .../testing/selftests/hid/progs/hid_bpf_helpers.h | 2 + 3 files changed, 110 insertions(+), 1 deletion(-)