Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/hid/hidraw.c
26302 views
1
// SPDX-License-Identifier: GPL-2.0
2
/* Copyright (c) 2022-2024 Red Hat */
3
4
#include "hid_common.h"
5
6
/* for older kernels */
7
#ifndef HIDIOCREVOKE
8
#define HIDIOCREVOKE _IOW('H', 0x0D, int) /* Revoke device access */
9
#endif /* HIDIOCREVOKE */
10
11
FIXTURE(hidraw) {
12
struct uhid_device hid;
13
int hidraw_fd;
14
};
15
static void close_hidraw(FIXTURE_DATA(hidraw) * self)
16
{
17
if (self->hidraw_fd)
18
close(self->hidraw_fd);
19
self->hidraw_fd = 0;
20
}
21
22
FIXTURE_TEARDOWN(hidraw) {
23
void *uhid_err;
24
25
uhid_destroy(_metadata, &self->hid);
26
27
close_hidraw(self);
28
pthread_join(self->hid.tid, &uhid_err);
29
}
30
#define TEARDOWN_LOG(fmt, ...) do { \
31
TH_LOG(fmt, ##__VA_ARGS__); \
32
hidraw_teardown(_metadata, self, variant); \
33
} while (0)
34
35
FIXTURE_SETUP(hidraw)
36
{
37
int err;
38
39
err = setup_uhid(_metadata, &self->hid, BUS_USB, 0x0001, 0x0a37, rdesc, sizeof(rdesc));
40
ASSERT_OK(err);
41
42
self->hidraw_fd = open_hidraw(&self->hid);
43
ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");
44
}
45
46
/*
47
* A simple test to see if the fixture is working fine.
48
* If this fails, none of the other tests will pass.
49
*/
50
TEST_F(hidraw, test_create_uhid)
51
{
52
}
53
54
/*
55
* Inject one event in the uhid device,
56
* check that we get the same data through hidraw
57
*/
58
TEST_F(hidraw, raw_event)
59
{
60
__u8 buf[10] = {0};
61
int err;
62
63
/* inject one event */
64
buf[0] = 1;
65
buf[1] = 42;
66
uhid_send_event(_metadata, &self->hid, buf, 6);
67
68
/* read the data from hidraw */
69
memset(buf, 0, sizeof(buf));
70
err = read(self->hidraw_fd, buf, sizeof(buf));
71
ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
72
ASSERT_EQ(buf[0], 1);
73
ASSERT_EQ(buf[1], 42);
74
}
75
76
/*
77
* After initial opening/checks of hidraw, revoke the hidraw
78
* node and check that we can not read any more data.
79
*/
80
TEST_F(hidraw, raw_event_revoked)
81
{
82
__u8 buf[10] = {0};
83
int err;
84
85
/* inject one event */
86
buf[0] = 1;
87
buf[1] = 42;
88
uhid_send_event(_metadata, &self->hid, buf, 6);
89
90
/* read the data from hidraw */
91
memset(buf, 0, sizeof(buf));
92
err = read(self->hidraw_fd, buf, sizeof(buf));
93
ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
94
ASSERT_EQ(buf[0], 1);
95
ASSERT_EQ(buf[1], 42);
96
97
/* call the revoke ioctl */
98
err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL);
99
ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd");
100
101
/* inject one other event */
102
buf[0] = 1;
103
buf[1] = 43;
104
uhid_send_event(_metadata, &self->hid, buf, 6);
105
106
/* read the data from hidraw */
107
memset(buf, 0, sizeof(buf));
108
err = read(self->hidraw_fd, buf, sizeof(buf));
109
ASSERT_EQ(err, -1) TH_LOG("read_hidraw");
110
ASSERT_EQ(errno, ENODEV) TH_LOG("unexpected error code while reading the hidraw node: %d",
111
errno);
112
}
113
114
/*
115
* Revoke the hidraw node and check that we can not do any ioctl.
116
*/
117
TEST_F(hidraw, ioctl_revoked)
118
{
119
int err, desc_size = 0;
120
121
/* call the revoke ioctl */
122
err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL);
123
ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd");
124
125
/* do an ioctl */
126
err = ioctl(self->hidraw_fd, HIDIOCGRDESCSIZE, &desc_size);
127
ASSERT_EQ(err, -1) TH_LOG("ioctl_hidraw");
128
ASSERT_EQ(errno, ENODEV) TH_LOG("unexpected error code while doing an ioctl: %d",
129
errno);
130
}
131
132
/*
133
* Setup polling of the fd, and check that revoke works properly.
134
*/
135
TEST_F(hidraw, poll_revoked)
136
{
137
struct pollfd pfds[1];
138
__u8 buf[10] = {0};
139
int err, ready;
140
141
/* setup polling */
142
pfds[0].fd = self->hidraw_fd;
143
pfds[0].events = POLLIN;
144
145
/* inject one event */
146
buf[0] = 1;
147
buf[1] = 42;
148
uhid_send_event(_metadata, &self->hid, buf, 6);
149
150
while (true) {
151
ready = poll(pfds, 1, 5000);
152
ASSERT_EQ(ready, 1) TH_LOG("poll return value");
153
154
if (pfds[0].revents & POLLIN) {
155
memset(buf, 0, sizeof(buf));
156
err = read(self->hidraw_fd, buf, sizeof(buf));
157
ASSERT_EQ(err, 6) TH_LOG("read_hidraw");
158
ASSERT_EQ(buf[0], 1);
159
ASSERT_EQ(buf[1], 42);
160
161
/* call the revoke ioctl */
162
err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL);
163
ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd");
164
} else {
165
break;
166
}
167
}
168
169
ASSERT_TRUE(pfds[0].revents & POLLHUP);
170
}
171
172
/*
173
* After initial opening/checks of hidraw, revoke the hidraw
174
* node and check that we can not read any more data.
175
*/
176
TEST_F(hidraw, write_event_revoked)
177
{
178
struct timespec time_to_wait;
179
__u8 buf[10] = {0};
180
int err;
181
182
/* inject one event from hidraw */
183
buf[0] = 1; /* report ID */
184
buf[1] = 2;
185
buf[2] = 42;
186
187
pthread_mutex_lock(&uhid_output_mtx);
188
189
memset(output_report, 0, sizeof(output_report));
190
clock_gettime(CLOCK_REALTIME, &time_to_wait);
191
time_to_wait.tv_sec += 2;
192
193
err = write(self->hidraw_fd, buf, 3);
194
ASSERT_EQ(err, 3) TH_LOG("unexpected error while writing to hidraw node: %d", err);
195
196
err = pthread_cond_timedwait(&uhid_output_cond, &uhid_output_mtx, &time_to_wait);
197
ASSERT_OK(err) TH_LOG("error while calling waiting for the condition");
198
199
ASSERT_EQ(output_report[0], 1);
200
ASSERT_EQ(output_report[1], 2);
201
ASSERT_EQ(output_report[2], 42);
202
203
/* call the revoke ioctl */
204
err = ioctl(self->hidraw_fd, HIDIOCREVOKE, NULL);
205
ASSERT_OK(err) TH_LOG("couldn't revoke the hidraw fd");
206
207
/* inject one other event */
208
buf[0] = 1;
209
buf[1] = 43;
210
err = write(self->hidraw_fd, buf, 3);
211
ASSERT_LT(err, 0) TH_LOG("unexpected success while writing to hidraw node: %d", err);
212
ASSERT_EQ(errno, ENODEV) TH_LOG("unexpected error code while writing to hidraw node: %d",
213
errno);
214
215
pthread_mutex_unlock(&uhid_output_mtx);
216
}
217
218
int main(int argc, char **argv)
219
{
220
return test_harness_run(argc, argv);
221
}
222
223