Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/hid: add report descriptor fixup tests

Simple report descriptor override in HID: replace part of the report
descriptor from a static definition in the bpf kernel program.

Note that this test should be run last because we disconnect/reconnect
the device, meaning that it changes the overall uhid device.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

authored by

Benjamin Tissoires and committed by
Jiri Kosina
e8445737 ad190df1

+85
+32
tools/testing/selftests/hid/hid_bpf.c
··· 740 740 ASSERT_EQ(args.data[1], 2); 741 741 } 742 742 743 + /* 744 + * Attach hid_rdesc_fixup to the given uhid device, 745 + * retrieve and open the matching hidraw node, 746 + * check that the hidraw report descriptor has been updated. 747 + */ 748 + TEST_F(hid_bpf, test_rdesc_fixup) 749 + { 750 + struct hidraw_report_descriptor rpt_desc = {0}; 751 + const struct test_program progs[] = { 752 + { .name = "hid_rdesc_fixup" }, 753 + }; 754 + int err, desc_size; 755 + 756 + LOAD_PROGRAMS(progs); 757 + 758 + /* check that hid_rdesc_fixup() was executed */ 759 + ASSERT_EQ(self->skel->data->callback2_check, 0x21); 760 + 761 + /* read the exposed report descriptor from hidraw */ 762 + err = ioctl(self->hidraw_fd, HIDIOCGRDESCSIZE, &desc_size); 763 + ASSERT_GE(err, 0) TH_LOG("error while reading HIDIOCGRDESCSIZE: %d", err); 764 + 765 + /* ensure the new size of the rdesc is bigger than the old one */ 766 + ASSERT_GT(desc_size, sizeof(rdesc)); 767 + 768 + rpt_desc.size = desc_size; 769 + err = ioctl(self->hidraw_fd, HIDIOCGRDESC, &rpt_desc); 770 + ASSERT_GE(err, 0) TH_LOG("error while reading HIDIOCGRDESC: %d", err); 771 + 772 + ASSERT_EQ(rpt_desc.value[4], 0x42); 773 + } 774 + 743 775 static int libbpf_print_fn(enum libbpf_print_level level, 744 776 const char *format, va_list args) 745 777 {
+53
tools/testing/selftests/hid/progs/hid.c
··· 88 88 89 89 return 0; 90 90 } 91 + 92 + static const __u8 rdesc[] = { 93 + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ 94 + 0x09, 0x32, /* USAGE (Z) */ 95 + 0x95, 0x01, /* REPORT_COUNT (1) */ 96 + 0x81, 0x06, /* INPUT (Data,Var,Rel) */ 97 + 98 + 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */ 99 + 0x19, 0x01, /* USAGE_MINIMUM (1) */ 100 + 0x29, 0x03, /* USAGE_MAXIMUM (3) */ 101 + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 102 + 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ 103 + 0x95, 0x03, /* REPORT_COUNT (3) */ 104 + 0x75, 0x01, /* REPORT_SIZE (1) */ 105 + 0x91, 0x02, /* Output (Data,Var,Abs) */ 106 + 0x95, 0x01, /* REPORT_COUNT (1) */ 107 + 0x75, 0x05, /* REPORT_SIZE (5) */ 108 + 0x91, 0x01, /* Output (Cnst,Var,Abs) */ 109 + 110 + 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */ 111 + 0x19, 0x06, /* USAGE_MINIMUM (6) */ 112 + 0x29, 0x08, /* USAGE_MAXIMUM (8) */ 113 + 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 114 + 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ 115 + 0x95, 0x03, /* REPORT_COUNT (3) */ 116 + 0x75, 0x01, /* REPORT_SIZE (1) */ 117 + 0xb1, 0x02, /* Feature (Data,Var,Abs) */ 118 + 0x95, 0x01, /* REPORT_COUNT (1) */ 119 + 0x75, 0x05, /* REPORT_SIZE (5) */ 120 + 0x91, 0x01, /* Output (Cnst,Var,Abs) */ 121 + 122 + 0xc0, /* END_COLLECTION */ 123 + 0xc0, /* END_COLLECTION */ 124 + }; 125 + 126 + SEC("?fmod_ret/hid_bpf_rdesc_fixup") 127 + int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hid_ctx) 128 + { 129 + __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, 4096 /* size */); 130 + 131 + if (!data) 132 + return 0; /* EPERM check */ 133 + 134 + callback2_check = data[4]; 135 + 136 + /* insert rdesc at offset 73 */ 137 + __builtin_memcpy(&data[73], rdesc, sizeof(rdesc)); 138 + 139 + /* Change Usage Vendor globally */ 140 + data[4] = 0x42; 141 + 142 + return sizeof(rdesc) + 73; 143 + }