xref: /linux/sound/core/sound_kunit.c (revision 9de7d0caefd0cdf6d3e301e3aad84fd9a5ce12e8)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Sound core KUnit test
4  * Author: Ivan Orlov <ivan.orlov0322@gmail.com>
5  */
6 
7 #include <kunit/test.h>
8 #include <sound/core.h>
9 #include <sound/pcm.h>
10 
11 #define SILENCE_BUFFER_SIZE 2048
12 #define SILENCE(...) { __VA_ARGS__ }
13 #define DEFINE_FORMAT(fmt, pbits, wd, endianness, signd, silence_arr) {		\
14 	.format = SNDRV_PCM_FORMAT_##fmt, .physical_bits = pbits,		\
15 	.width = wd, .le = endianness, .sd = signd, .silence = silence_arr,	\
16 	.name = #fmt,								\
17 }
18 
19 #define WRONG_FORMAT (SNDRV_PCM_FORMAT_LAST + 1)
20 
21 #define VALID_NAME "ValidName"
22 #define NAME_W_SPEC_CHARS "In%v@1id name"
23 #define NAME_W_SPACE "Test name"
24 #define NAME_W_SPACE_REMOVED "Testname"
25 
26 #define TEST_FIRST_COMPONENT "Component1"
27 #define TEST_SECOND_COMPONENT "Component2"
28 
29 struct snd_format_test_data {
30 	snd_pcm_format_t format;
31 	int physical_bits;
32 	int width;
33 	int le;
34 	int sd;
35 	unsigned char silence[8];
36 	unsigned char *name;
37 };
38 
39 struct avail_test_data {
40 	snd_pcm_uframes_t buffer_size;
41 	snd_pcm_uframes_t hw_ptr;
42 	snd_pcm_uframes_t appl_ptr;
43 	snd_pcm_uframes_t expected_avail;
44 };
45 
46 static struct snd_format_test_data valid_fmt[] = {
47 	DEFINE_FORMAT(S8, 8, 8, -1, 1, SILENCE()),
48 	DEFINE_FORMAT(U8, 8, 8, -1, 0, SILENCE(0x80)),
49 	DEFINE_FORMAT(S16_LE, 16, 16, 1, 1, SILENCE()),
50 	DEFINE_FORMAT(S16_BE, 16, 16, 0, 1, SILENCE()),
51 	DEFINE_FORMAT(U16_LE, 16, 16, 1, 0, SILENCE(0x00, 0x80)),
52 	DEFINE_FORMAT(U16_BE, 16, 16, 0, 0, SILENCE(0x80, 0x00)),
53 	DEFINE_FORMAT(S24_LE, 32, 24, 1, 1, SILENCE()),
54 	DEFINE_FORMAT(S24_BE, 32, 24, 0, 1, SILENCE()),
55 	DEFINE_FORMAT(U24_LE, 32, 24, 1, 0, SILENCE(0x00, 0x00, 0x80)),
56 	DEFINE_FORMAT(U24_BE, 32, 24, 0, 0, SILENCE(0x00, 0x80, 0x00, 0x00)),
57 	DEFINE_FORMAT(S32_LE, 32, 32, 1, 1, SILENCE()),
58 	DEFINE_FORMAT(S32_BE, 32, 32, 0, 1, SILENCE()),
59 	DEFINE_FORMAT(U32_LE, 32, 32, 1, 0, SILENCE(0x00, 0x00, 0x00, 0x80)),
60 	DEFINE_FORMAT(U32_BE, 32, 32, 0, 0, SILENCE(0x80, 0x00, 0x00, 0x00)),
61 	DEFINE_FORMAT(FLOAT_LE, 32, 32, 1, -1, SILENCE()),
62 	DEFINE_FORMAT(FLOAT_BE, 32, 32, 0, -1, SILENCE()),
63 	DEFINE_FORMAT(FLOAT64_LE, 64, 64, 1, -1, SILENCE()),
64 	DEFINE_FORMAT(FLOAT64_BE, 64, 64, 0, -1, SILENCE()),
65 	DEFINE_FORMAT(IEC958_SUBFRAME_LE, 32, 32, 1, -1, SILENCE()),
66 	DEFINE_FORMAT(IEC958_SUBFRAME_BE, 32, 32, 0, -1, SILENCE()),
67 	DEFINE_FORMAT(MU_LAW, 8, 8, -1, -1, SILENCE(0x7f)),
68 	DEFINE_FORMAT(A_LAW, 8, 8, -1, -1, SILENCE(0x55)),
69 	DEFINE_FORMAT(IMA_ADPCM, 4, 4, -1, -1, SILENCE()),
70 	DEFINE_FORMAT(G723_24, 3, 3, -1, -1, SILENCE()),
71 	DEFINE_FORMAT(G723_40, 5, 5, -1, -1, SILENCE()),
72 	DEFINE_FORMAT(DSD_U8, 8, 8, 1, 0, SILENCE(0x69)),
73 	DEFINE_FORMAT(DSD_U16_LE, 16, 16, 1, 0, SILENCE(0x69, 0x69)),
74 	DEFINE_FORMAT(DSD_U32_LE, 32, 32, 1, 0, SILENCE(0x69, 0x69, 0x69, 0x69)),
75 	DEFINE_FORMAT(DSD_U16_BE, 16, 16, 0, 0, SILENCE(0x69, 0x69)),
76 	DEFINE_FORMAT(DSD_U32_BE, 32, 32, 0, 0, SILENCE(0x69, 0x69, 0x69, 0x69)),
77 	DEFINE_FORMAT(S20_LE, 32, 20, 1, 1, SILENCE()),
78 	DEFINE_FORMAT(S20_BE, 32, 20, 0, 1, SILENCE()),
79 	DEFINE_FORMAT(U20_LE, 32, 20, 1, 0, SILENCE(0x00, 0x00, 0x08, 0x00)),
80 	DEFINE_FORMAT(U20_BE, 32, 20, 0, 0, SILENCE(0x00, 0x08, 0x00, 0x00)),
81 	DEFINE_FORMAT(S24_3LE, 24, 24, 1, 1, SILENCE()),
82 	DEFINE_FORMAT(S24_3BE, 24, 24, 0, 1, SILENCE()),
83 	DEFINE_FORMAT(U24_3LE, 24, 24, 1, 0, SILENCE(0x00, 0x00, 0x80)),
84 	DEFINE_FORMAT(U24_3BE, 24, 24, 0, 0, SILENCE(0x80, 0x00, 0x00)),
85 	DEFINE_FORMAT(S20_3LE, 24, 20, 1, 1, SILENCE()),
86 	DEFINE_FORMAT(S20_3BE, 24, 20, 0, 1, SILENCE()),
87 	DEFINE_FORMAT(U20_3LE, 24, 20, 1, 0, SILENCE(0x00, 0x00, 0x08)),
88 	DEFINE_FORMAT(U20_3BE, 24, 20, 0, 0, SILENCE(0x08, 0x00, 0x00)),
89 	DEFINE_FORMAT(S18_3LE, 24, 18, 1, 1, SILENCE()),
90 	DEFINE_FORMAT(S18_3BE, 24, 18, 0, 1, SILENCE()),
91 	DEFINE_FORMAT(U18_3LE, 24, 18, 1, 0, SILENCE(0x00, 0x00, 0x02)),
92 	DEFINE_FORMAT(U18_3BE, 24, 18, 0, 0, SILENCE(0x02, 0x00, 0x00)),
93 	DEFINE_FORMAT(G723_24_1B, 8, 3, -1, -1, SILENCE()),
94 	DEFINE_FORMAT(G723_40_1B, 8, 5, -1, -1, SILENCE()),
95 };
96 
97 static void test_phys_format_size(struct kunit *test)
98 {
99 	u32 i;
100 
101 	for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
102 		KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(valid_fmt[i].format),
103 				valid_fmt[i].physical_bits);
104 	}
105 
106 	KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(WRONG_FORMAT), -EINVAL);
107 	KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(-1), -EINVAL);
108 }
109 
110 static void test_format_width(struct kunit *test)
111 {
112 	u32 i;
113 
114 	for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
115 		KUNIT_EXPECT_EQ(test, snd_pcm_format_width(valid_fmt[i].format),
116 				valid_fmt[i].width);
117 	}
118 
119 	KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT), -EINVAL);
120 	KUNIT_EXPECT_EQ(test, snd_pcm_format_width(-1), -EINVAL);
121 }
122 
123 static void test_format_signed(struct kunit *test)
124 {
125 	u32 i;
126 
127 	for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
128 		KUNIT_EXPECT_EQ(test, snd_pcm_format_signed(valid_fmt[i].format),
129 				valid_fmt[i].sd < 0 ? -EINVAL : valid_fmt[i].sd);
130 		KUNIT_EXPECT_EQ(test, snd_pcm_format_unsigned(valid_fmt[i].format),
131 				valid_fmt[i].sd < 0 ? -EINVAL : 1 - valid_fmt[i].sd);
132 	}
133 
134 	KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT), -EINVAL);
135 	KUNIT_EXPECT_EQ(test, snd_pcm_format_width(-1), -EINVAL);
136 }
137 
138 static void test_format_endianness(struct kunit *test)
139 {
140 	u32 i;
141 
142 	for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
143 		KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(valid_fmt[i].format),
144 				valid_fmt[i].le < 0 ? -EINVAL : valid_fmt[i].le);
145 		KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(valid_fmt[i].format),
146 				valid_fmt[i].le < 0 ? -EINVAL : 1 - valid_fmt[i].le);
147 	}
148 
149 	KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(WRONG_FORMAT), -EINVAL);
150 	KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(-1), -EINVAL);
151 	KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(WRONG_FORMAT), -EINVAL);
152 	KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(-1), -EINVAL);
153 }
154 
155 static void _test_fill_silence(struct kunit *test, struct snd_format_test_data *data,
156 			       u8 *buffer, size_t samples_count)
157 {
158 	size_t sample_bytes = data->physical_bits >> 3;
159 	u32 i;
160 
161 	KUNIT_ASSERT_EQ(test, snd_pcm_format_set_silence(data->format, buffer, samples_count), 0);
162 	for (i = 0; i < samples_count * sample_bytes; i++)
163 		KUNIT_EXPECT_EQ(test, buffer[i], data->silence[i % sample_bytes]);
164 }
165 
166 static void test_format_fill_silence(struct kunit *test)
167 {
168 	u32 buf_samples[] = { 10, 20, 32, 64, 129, 260 };
169 	u8 *buffer;
170 	u32 i, j;
171 
172 	buffer = kunit_kzalloc(test, SILENCE_BUFFER_SIZE, GFP_KERNEL);
173 
174 	for (i = 0; i < ARRAY_SIZE(buf_samples); i++) {
175 		for (j = 0; j < ARRAY_SIZE(valid_fmt); j++)
176 			_test_fill_silence(test, &valid_fmt[j], buffer, buf_samples[i]);
177 	}
178 
179 	KUNIT_EXPECT_EQ(test, snd_pcm_format_set_silence(WRONG_FORMAT, buffer, 20), -EINVAL);
180 	KUNIT_EXPECT_EQ(test, snd_pcm_format_set_silence(SNDRV_PCM_FORMAT_LAST, buffer, 0), 0);
181 }
182 
183 static snd_pcm_uframes_t calculate_boundary(snd_pcm_uframes_t buffer_size)
184 {
185 	snd_pcm_uframes_t boundary = buffer_size;
186 
187 	while (boundary * 2 <= 0x7fffffffUL - buffer_size)
188 		boundary *= 2;
189 	return boundary;
190 }
191 
192 static struct avail_test_data p_avail_data[] = {
193 	/* buf_size + hw_ptr < appl_ptr => avail = buf_size + hw_ptr - appl_ptr + boundary */
194 	{ 128, 1000, 1129, 1073741824UL - 1 },
195 	/*
196 	 * buf_size + hw_ptr - appl_ptr >= boundary =>
197 	 * => avail = buf_size + hw_ptr - appl_ptr - boundary
198 	 */
199 	{ 128, 1073741824UL, 10, 118 },
200 	/* standard case: avail = buf_size + hw_ptr - appl_ptr */
201 	{ 128, 1000, 1001, 127 },
202 };
203 
204 static void test_playback_avail(struct kunit *test)
205 {
206 	struct snd_pcm_runtime *r = kunit_kzalloc(test, sizeof(*r), GFP_KERNEL);
207 	u32 i;
208 
209 	r->status = kunit_kzalloc(test, sizeof(*r->status), GFP_KERNEL);
210 	r->control = kunit_kzalloc(test, sizeof(*r->control), GFP_KERNEL);
211 
212 	for (i = 0; i < ARRAY_SIZE(p_avail_data); i++) {
213 		r->buffer_size = p_avail_data[i].buffer_size;
214 		r->boundary = calculate_boundary(r->buffer_size);
215 		r->status->hw_ptr = p_avail_data[i].hw_ptr;
216 		r->control->appl_ptr = p_avail_data[i].appl_ptr;
217 		KUNIT_EXPECT_EQ(test, snd_pcm_playback_avail(r), p_avail_data[i].expected_avail);
218 	}
219 }
220 
221 static struct avail_test_data c_avail_data[] = {
222 	/* hw_ptr - appl_ptr < 0 => avail = hw_ptr - appl_ptr + boundary */
223 	{ 128, 1000, 1001, 1073741824UL - 1 },
224 	/* standard case: avail = hw_ptr - appl_ptr */
225 	{ 128, 1001, 1000, 1 },
226 };
227 
228 static void test_capture_avail(struct kunit *test)
229 {
230 	struct snd_pcm_runtime *r = kunit_kzalloc(test, sizeof(*r), GFP_KERNEL);
231 	u32 i;
232 
233 	r->status = kunit_kzalloc(test, sizeof(*r->status), GFP_KERNEL);
234 	r->control = kunit_kzalloc(test, sizeof(*r->control), GFP_KERNEL);
235 
236 	for (i = 0; i < ARRAY_SIZE(c_avail_data); i++) {
237 		r->buffer_size = c_avail_data[i].buffer_size;
238 		r->boundary = calculate_boundary(r->buffer_size);
239 		r->status->hw_ptr = c_avail_data[i].hw_ptr;
240 		r->control->appl_ptr = c_avail_data[i].appl_ptr;
241 		KUNIT_EXPECT_EQ(test, snd_pcm_capture_avail(r), c_avail_data[i].expected_avail);
242 	}
243 }
244 
245 static void test_card_set_id(struct kunit *test)
246 {
247 	struct snd_card *card = kunit_kzalloc(test, sizeof(*card), GFP_KERNEL);
248 
249 	snd_card_set_id(card, VALID_NAME);
250 	KUNIT_EXPECT_STREQ(test, card->id, VALID_NAME);
251 
252 	/* clear the first id character so we can set it again */
253 	card->id[0] = '\0';
254 	snd_card_set_id(card, NAME_W_SPEC_CHARS);
255 	KUNIT_EXPECT_STRNEQ(test, card->id, NAME_W_SPEC_CHARS);
256 
257 	card->id[0] = '\0';
258 	snd_card_set_id(card, NAME_W_SPACE);
259 	kunit_info(test, "%s", card->id);
260 	KUNIT_EXPECT_STREQ(test, card->id, NAME_W_SPACE_REMOVED);
261 }
262 
263 static void test_pcm_format_name(struct kunit *test)
264 {
265 	u32 i;
266 	const char *name;
267 
268 	for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) {
269 		name = snd_pcm_format_name(valid_fmt[i].format);
270 		KUNIT_ASSERT_NOT_NULL_MSG(test, name, "Don't have name for %s", valid_fmt[i].name);
271 		KUNIT_EXPECT_STREQ(test, name, valid_fmt[i].name);
272 	}
273 
274 	KUNIT_ASSERT_STREQ(test, snd_pcm_format_name(WRONG_FORMAT), "Unknown");
275 	KUNIT_ASSERT_STREQ(test, snd_pcm_format_name(-1), "Unknown");
276 }
277 
278 static void test_card_add_component(struct kunit *test)
279 {
280 	struct snd_card *card = kunit_kzalloc(test, sizeof(*card), GFP_KERNEL);
281 
282 	snd_component_add(card, TEST_FIRST_COMPONENT);
283 	KUNIT_ASSERT_STREQ(test, card->components, TEST_FIRST_COMPONENT);
284 
285 	snd_component_add(card, TEST_SECOND_COMPONENT);
286 	KUNIT_ASSERT_STREQ(test, card->components, TEST_FIRST_COMPONENT " " TEST_SECOND_COMPONENT);
287 }
288 
289 static struct kunit_case sound_utils_cases[] = {
290 	KUNIT_CASE(test_phys_format_size),
291 	KUNIT_CASE(test_format_width),
292 	KUNIT_CASE(test_format_endianness),
293 	KUNIT_CASE(test_format_signed),
294 	KUNIT_CASE(test_format_fill_silence),
295 	KUNIT_CASE(test_playback_avail),
296 	KUNIT_CASE(test_capture_avail),
297 	KUNIT_CASE(test_card_set_id),
298 	KUNIT_CASE(test_pcm_format_name),
299 	KUNIT_CASE(test_card_add_component),
300 	{},
301 };
302 
303 static struct kunit_suite sound_utils_suite = {
304 	.name = "sound-core-test",
305 	.test_cases = sound_utils_cases,
306 };
307 
308 kunit_test_suite(sound_utils_suite);
309 MODULE_AUTHOR("Ivan Orlov");
310 MODULE_LICENSE("GPL");
311