Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/ir/ir_loopback.c
26285 views
1
// SPDX-License-Identifier: GPL-2.0
2
// test ir decoder
3
//
4
// Copyright (C) 2018 Sean Young <[email protected]>
5
6
// When sending LIRC_MODE_SCANCODE, the IR will be encoded. rc-loopback
7
// will send this IR to the receiver side, where we try to read the decoded
8
// IR. Decoding happens in a separate kernel thread, so we will need to
9
// wait until that is scheduled, hence we use poll to check for read
10
// readiness.
11
12
#include <linux/lirc.h>
13
#include <errno.h>
14
#include <stdio.h>
15
#include <stdlib.h>
16
#include <stdbool.h>
17
#include <string.h>
18
#include <unistd.h>
19
#include <poll.h>
20
#include <time.h>
21
#include <sys/types.h>
22
#include <sys/ioctl.h>
23
#include <dirent.h>
24
#include <sys/stat.h>
25
#include <fcntl.h>
26
#include "../kselftest.h"
27
28
#define TEST_SCANCODES 10
29
#define SYSFS_PATH_MAX 256
30
#define DNAME_PATH_MAX 256
31
32
/*
33
* Support ancient lirc.h which does not have these values. Can be removed
34
* once RHEL 8 is no longer a relevant testing platform.
35
*/
36
#if RC_PROTO_MAX < 26
37
#define RC_PROTO_RCMM12 24
38
#define RC_PROTO_RCMM24 25
39
#define RC_PROTO_RCMM32 26
40
#endif
41
42
static const struct {
43
enum rc_proto proto;
44
const char *name;
45
unsigned int mask;
46
const char *decoder;
47
} protocols[] = {
48
{ RC_PROTO_RC5, "rc-5", 0x1f7f, "rc-5" },
49
{ RC_PROTO_RC5X_20, "rc-5x-20", 0x1f7f3f, "rc-5" },
50
{ RC_PROTO_RC5_SZ, "rc-5-sz", 0x2fff, "rc-5-sz" },
51
{ RC_PROTO_JVC, "jvc", 0xffff, "jvc" },
52
{ RC_PROTO_SONY12, "sony-12", 0x1f007f, "sony" },
53
{ RC_PROTO_SONY15, "sony-15", 0xff007f, "sony" },
54
{ RC_PROTO_SONY20, "sony-20", 0x1fff7f, "sony" },
55
{ RC_PROTO_NEC, "nec", 0xffff, "nec" },
56
{ RC_PROTO_NECX, "nec-x", 0xffffff, "nec" },
57
{ RC_PROTO_NEC32, "nec-32", 0xffffffff, "nec" },
58
{ RC_PROTO_SANYO, "sanyo", 0x1fffff, "sanyo" },
59
{ RC_PROTO_RC6_0, "rc-6-0", 0xffff, "rc-6" },
60
{ RC_PROTO_RC6_6A_20, "rc-6-6a-20", 0xfffff, "rc-6" },
61
{ RC_PROTO_RC6_6A_24, "rc-6-6a-24", 0xffffff, "rc-6" },
62
{ RC_PROTO_RC6_6A_32, "rc-6-6a-32", 0xffffffff, "rc-6" },
63
{ RC_PROTO_RC6_MCE, "rc-6-mce", 0x00007fff, "rc-6" },
64
{ RC_PROTO_SHARP, "sharp", 0x1fff, "sharp" },
65
{ RC_PROTO_IMON, "imon", 0x7fffffff, "imon" },
66
{ RC_PROTO_RCMM12, "rcmm-12", 0x00000fff, "rc-mm" },
67
{ RC_PROTO_RCMM24, "rcmm-24", 0x00ffffff, "rc-mm" },
68
{ RC_PROTO_RCMM32, "rcmm-32", 0xffffffff, "rc-mm" },
69
};
70
71
int lirc_open(const char *rc)
72
{
73
struct dirent *dent;
74
char buf[SYSFS_PATH_MAX + DNAME_PATH_MAX];
75
DIR *d;
76
int fd;
77
78
snprintf(buf, sizeof(buf), "/sys/class/rc/%s", rc);
79
80
d = opendir(buf);
81
if (!d)
82
ksft_exit_fail_msg("cannot open %s: %m\n", buf);
83
84
while ((dent = readdir(d)) != NULL) {
85
if (!strncmp(dent->d_name, "lirc", 4)) {
86
snprintf(buf, sizeof(buf), "/dev/%s", dent->d_name);
87
break;
88
}
89
}
90
91
if (!dent)
92
ksft_exit_skip("cannot find lirc device for %s\n", rc);
93
94
closedir(d);
95
96
fd = open(buf, O_RDWR | O_NONBLOCK);
97
if (fd == -1)
98
ksft_exit_fail_msg("cannot open: %s: %m\n", buf);
99
100
return fd;
101
}
102
103
int main(int argc, char **argv)
104
{
105
unsigned int mode;
106
char buf[100];
107
int rlircfd, wlircfd, protocolfd, i, n;
108
109
srand(time(NULL));
110
111
if (argc != 3)
112
ksft_exit_fail_msg("Usage: %s <write rcN> <read rcN>\n",
113
argv[0]);
114
115
rlircfd = lirc_open(argv[2]);
116
mode = LIRC_MODE_SCANCODE;
117
if (ioctl(rlircfd, LIRC_SET_REC_MODE, &mode))
118
ksft_exit_fail_msg("failed to set scancode rec mode %s: %m\n",
119
argv[2]);
120
121
wlircfd = lirc_open(argv[1]);
122
if (ioctl(wlircfd, LIRC_SET_SEND_MODE, &mode))
123
ksft_exit_fail_msg("failed to set scancode send mode %s: %m\n",
124
argv[1]);
125
126
snprintf(buf, sizeof(buf), "/sys/class/rc/%s/protocols", argv[2]);
127
protocolfd = open(buf, O_WRONLY);
128
if (protocolfd == -1)
129
ksft_exit_fail_msg("failed to open %s: %m\n", buf);
130
131
printf("Sending IR on %s and receiving IR on %s.\n", argv[1], argv[2]);
132
133
for (i = 0; i < ARRAY_SIZE(protocols); i++) {
134
if (write(protocolfd, protocols[i].decoder,
135
strlen(protocols[i].decoder)) == -1)
136
ksft_exit_fail_msg("failed to set write decoder\n");
137
138
printf("Testing protocol %s for decoder %s (%d/%d)...\n",
139
protocols[i].name, protocols[i].decoder,
140
i + 1, (int)ARRAY_SIZE(protocols));
141
142
for (n = 0; n < TEST_SCANCODES; n++) {
143
unsigned int scancode = rand() & protocols[i].mask;
144
unsigned int rc_proto = protocols[i].proto;
145
146
if (rc_proto == RC_PROTO_RC6_MCE)
147
scancode |= 0x800f0000;
148
149
if (rc_proto == RC_PROTO_NECX &&
150
(((scancode >> 16) ^ ~(scancode >> 8)) & 0xff) == 0)
151
continue;
152
153
if (rc_proto == RC_PROTO_NEC32 &&
154
(((scancode >> 8) ^ ~scancode) & 0xff) == 0)
155
continue;
156
157
if (rc_proto == RC_PROTO_RCMM32 &&
158
(scancode & 0x000c0000) != 0x000c0000 &&
159
scancode & 0x00008000)
160
continue;
161
162
struct lirc_scancode lsc = {
163
.rc_proto = rc_proto,
164
.scancode = scancode
165
};
166
167
printf("Testing scancode:%x\n", scancode);
168
169
while (write(wlircfd, &lsc, sizeof(lsc)) < 0) {
170
if (errno == EINTR)
171
continue;
172
173
ksft_exit_fail_msg("failed to send ir: %m\n");
174
}
175
176
struct pollfd pfd = { .fd = rlircfd, .events = POLLIN };
177
struct lirc_scancode lsc2;
178
179
poll(&pfd, 1, 1000);
180
181
bool decoded = true;
182
183
while (read(rlircfd, &lsc2, sizeof(lsc2)) < 0) {
184
if (errno == EINTR)
185
continue;
186
187
ksft_test_result_error("no scancode decoded: %m\n");
188
decoded = false;
189
break;
190
}
191
192
if (!decoded)
193
continue;
194
195
if (lsc.rc_proto != lsc2.rc_proto)
196
ksft_test_result_error("decoded protocol is different: %d\n",
197
lsc2.rc_proto);
198
199
else if (lsc.scancode != lsc2.scancode)
200
ksft_test_result_error("decoded scancode is different: %llx\n",
201
lsc2.scancode);
202
else
203
ksft_inc_pass_cnt();
204
}
205
206
printf("OK\n");
207
}
208
209
close(rlircfd);
210
close(wlircfd);
211
close(protocolfd);
212
213
if (ksft_get_fail_cnt() > 0)
214
ksft_exit_fail();
215
else
216
ksft_exit_pass();
217
218
return 0;
219
}
220
221