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 <bent...@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(-)

diff --git a/tools/testing/selftests/hid/hid_bpf.c 
b/tools/testing/selftests/hid/hid_bpf.c
index 7eb15da62bdc..edc061b38528 100644
--- a/tools/testing/selftests/hid/hid_bpf.c
+++ b/tools/testing/selftests/hid/hid_bpf.c
@@ -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,
diff --git a/tools/testing/selftests/hid/progs/hid.c 
b/tools/testing/selftests/hid/progs/hid.c
index 5ecc845ef792..883d09498351 100644
--- a/tools/testing/selftests/hid/progs/hid.c
+++ b/tools/testing/selftests/hid/progs/hid.c
@@ -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,
+};
diff --git a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h 
b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
index e5db897586bb..6b0f870d0727 100644
--- a/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
+++ b/tools/testing/selftests/hid/progs/hid_bpf_helpers.h
@@ -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;
 };
 

-- 
2.46.0


Reply via email to