1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Virtual ALSA driver for PCM testing/fuzzing
4 *
5 * Copyright 2023 Ivan Orlov <ivan.orlov0322@gmail.com>
6 *
7 * This is a simple virtual ALSA driver, which can be used for audio applications/PCM middle layer
8 * testing or fuzzing.
9 * It can:
10 * - Simulate 'playback' and 'capture' actions
11 * - Generate random or pattern-based capture data
12 * - Check playback buffer for containing looped template, and notify about the results
13 * through the debugfs entry
14 * - Inject delays into the playback and capturing processes. See 'inject_delay' parameter.
15 * - Inject errors during the PCM callbacks.
16 * - Register custom RESET ioctl and notify when it is called through the debugfs entry
17 * - Work in interleaved and non-interleaved modes
18 * - Support up to 8 substreams
19 * - Support up to 4 channels
20 * - Support framerates from 8 kHz to 48 kHz
21 *
22 * When driver works in the capture mode with multiple channels, it duplicates the looped
23 * pattern to each separate channel. For example, if we have 2 channels, format = U8, interleaved
24 * access mode and pattern 'abacaba', the DMA buffer will look like aabbccaabbaaaa..., so buffer for
25 * each channel will contain abacabaabacaba... Same for the non-interleaved mode.
26 *
27 * However, it may break the capturing on the higher framerates with small period size, so it is
28 * better to choose larger period sizes.
29 *
30 * You can find the corresponding selftest in the 'alsa' selftests folder.
31 */
32
33 #include <linux/module.h>
34 #include <linux/init.h>
35 #include <sound/pcm.h>
36 #include <sound/core.h>
37 #include <linux/dma-mapping.h>
38 #include <linux/platform_device.h>
39 #include <linux/string.h>
40 #include <linux/timer.h>
41 #include <linux/random.h>
42 #include <linux/debugfs.h>
43 #include <linux/delay.h>
44
45 #define TIMER_PER_SEC 5
46 #define TIMER_INTERVAL (HZ / TIMER_PER_SEC)
47 #define DELAY_JIFFIES HZ
48 #define PLAYBACK_SUBSTREAM_CNT 8
49 #define CAPTURE_SUBSTREAM_CNT 8
50 #define MAX_CHANNELS_NUM 4
51
52 #define DEFAULT_PATTERN "abacaba"
53 #define DEFAULT_PATTERN_LEN 7
54
55 #define FILL_MODE_RAND 0
56 #define FILL_MODE_PAT 1
57
58 #define MAX_PATTERN_LEN 4096
59
60 static int index = -1;
61 static char *id = "pcmtest";
62 static bool enable = true;
63 static int inject_delay;
64 static bool inject_hwpars_err;
65 static bool inject_prepare_err;
66 static bool inject_trigger_err;
67 static bool inject_open_err;
68
69 static short fill_mode = FILL_MODE_PAT;
70
71 static u8 playback_capture_test;
72 static u8 ioctl_reset_test;
73 static struct dentry *driver_debug_dir;
74
75 module_param(index, int, 0444);
76 MODULE_PARM_DESC(index, "Index value for pcmtest soundcard");
77 module_param(id, charp, 0444);
78 MODULE_PARM_DESC(id, "ID string for pcmtest soundcard");
79 module_param(enable, bool, 0444);
80 MODULE_PARM_DESC(enable, "Enable pcmtest soundcard.");
81 module_param(fill_mode, short, 0600);
82 MODULE_PARM_DESC(fill_mode, "Buffer fill mode: rand(0) or pattern(1)");
83 module_param(inject_delay, int, 0600);
84 MODULE_PARM_DESC(inject_delay, "Inject delays during playback/capture (in jiffies)");
85 module_param(inject_hwpars_err, bool, 0600);
86 MODULE_PARM_DESC(inject_hwpars_err, "Inject EBUSY error in the 'hw_params' callback");
87 module_param(inject_prepare_err, bool, 0600);
88 MODULE_PARM_DESC(inject_prepare_err, "Inject EINVAL error in the 'prepare' callback");
89 module_param(inject_trigger_err, bool, 0600);
90 MODULE_PARM_DESC(inject_trigger_err, "Inject EINVAL error in the 'trigger' callback");
91 module_param(inject_open_err, bool, 0600);
92 MODULE_PARM_DESC(inject_open_err, "Inject EBUSY error in the 'open' callback");
93
94 struct pcmtst {
95 struct snd_pcm *pcm;
96 struct snd_card *card;
97 struct platform_device *pdev;
98 };
99
100 struct pcmtst_buf_iter {
101 size_t buf_pos; // position in the DMA buffer
102 size_t period_pos; // period-relative position
103 size_t b_rw; // Bytes to write on every timer tick
104 size_t s_rw_ch; // Samples to write to one channel on every tick
105 unsigned int sample_bytes; // sample_bits / 8
106 bool is_buf_corrupted; // playback test result indicator
107 size_t period_bytes; // bytes in a one period
108 bool interleaved; // Interleaved/Non-interleaved mode
109 size_t total_bytes; // Total bytes read/written
110 size_t chan_block; // Bytes in one channel buffer when non-interleaved
111 struct snd_pcm_substream *substream;
112 bool suspend; // We need to pause timer without shutting it down
113 struct timer_list timer_instance;
114 };
115
116 static struct snd_pcm_hardware snd_pcmtst_hw = {
117 .info = (SNDRV_PCM_INFO_INTERLEAVED |
118 SNDRV_PCM_INFO_BLOCK_TRANSFER |
119 SNDRV_PCM_INFO_NONINTERLEAVED |
120 SNDRV_PCM_INFO_MMAP_VALID |
121 SNDRV_PCM_INFO_PAUSE),
122 .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
123 .rates = SNDRV_PCM_RATE_8000_48000,
124 .rate_min = 8000,
125 .rate_max = 48000,
126 .channels_min = 1,
127 .channels_max = MAX_CHANNELS_NUM,
128 .buffer_bytes_max = 128 * 1024,
129 .period_bytes_min = 4096,
130 .period_bytes_max = 32768,
131 .periods_min = 1,
132 .periods_max = 1024,
133 };
134
135 struct pattern_buf {
136 char *buf;
137 u32 len;
138 };
139
140 static int buf_allocated;
141 static struct pattern_buf patt_bufs[MAX_CHANNELS_NUM];
142
inc_buf_pos(struct pcmtst_buf_iter * v_iter,size_t by,size_t bytes)143 static inline void inc_buf_pos(struct pcmtst_buf_iter *v_iter, size_t by, size_t bytes)
144 {
145 v_iter->total_bytes += by;
146 v_iter->buf_pos += by;
147 if (v_iter->buf_pos >= bytes)
148 v_iter->buf_pos %= bytes;
149 }
150
151 /*
152 * Position in the DMA buffer when we are in the non-interleaved mode. We increment buf_pos
153 * every time we write a byte to any channel, so the position in the current channel buffer is
154 * (position in the DMA buffer) / count_of_channels + size_of_channel_buf * current_channel
155 */
buf_pos_n(struct pcmtst_buf_iter * v_iter,unsigned int channels,unsigned int chan_num)156 static inline size_t buf_pos_n(struct pcmtst_buf_iter *v_iter, unsigned int channels,
157 unsigned int chan_num)
158 {
159 return v_iter->buf_pos / channels + v_iter->chan_block * chan_num;
160 }
161
162 /*
163 * Get the count of bytes written for the current channel in the interleaved mode.
164 * This is (count of samples written for the current channel) * bytes_in_sample +
165 * (relative position in the current sample)
166 */
ch_pos_i(size_t b_total,unsigned int channels,unsigned int b_sample)167 static inline size_t ch_pos_i(size_t b_total, unsigned int channels, unsigned int b_sample)
168 {
169 return b_total / channels / b_sample * b_sample + (b_total % b_sample);
170 }
171
check_buf_block_i(struct pcmtst_buf_iter * v_iter,struct snd_pcm_runtime * runtime)172 static void check_buf_block_i(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
173 {
174 size_t i;
175 short ch_num;
176 u8 current_byte;
177
178 for (i = 0; i < v_iter->b_rw; i++) {
179 current_byte = runtime->dma_area[v_iter->buf_pos];
180 if (!current_byte)
181 break;
182 ch_num = (v_iter->total_bytes / v_iter->sample_bytes) % runtime->channels;
183 if (current_byte != patt_bufs[ch_num].buf[ch_pos_i(v_iter->total_bytes,
184 runtime->channels,
185 v_iter->sample_bytes)
186 % patt_bufs[ch_num].len]) {
187 v_iter->is_buf_corrupted = true;
188 break;
189 }
190 inc_buf_pos(v_iter, 1, runtime->dma_bytes);
191 }
192 // If we broke during the loop, add remaining bytes to the buffer position.
193 inc_buf_pos(v_iter, v_iter->b_rw - i, runtime->dma_bytes);
194 }
195
check_buf_block_ni(struct pcmtst_buf_iter * v_iter,struct snd_pcm_runtime * runtime)196 static void check_buf_block_ni(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
197 {
198 unsigned int channels = runtime->channels;
199 size_t i;
200 short ch_num;
201 u8 current_byte;
202
203 for (i = 0; i < v_iter->b_rw; i++) {
204 ch_num = i % channels;
205 current_byte = runtime->dma_area[buf_pos_n(v_iter, channels, ch_num)];
206 if (!current_byte)
207 break;
208 if (current_byte != patt_bufs[ch_num].buf[(v_iter->total_bytes / channels)
209 % patt_bufs[ch_num].len]) {
210 v_iter->is_buf_corrupted = true;
211 break;
212 }
213 inc_buf_pos(v_iter, 1, runtime->dma_bytes);
214 }
215 inc_buf_pos(v_iter, v_iter->b_rw - i, runtime->dma_bytes);
216 }
217
218 /*
219 * Check one block of the buffer. Here we iterate the buffer until we find '0'. This condition is
220 * necessary because we need to detect when the reading/writing ends, so we assume that the pattern
221 * doesn't contain zeros.
222 */
check_buf_block(struct pcmtst_buf_iter * v_iter,struct snd_pcm_runtime * runtime)223 static void check_buf_block(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
224 {
225 if (v_iter->interleaved)
226 check_buf_block_i(v_iter, runtime);
227 else
228 check_buf_block_ni(v_iter, runtime);
229 }
230
231 /*
232 * Fill buffer in the non-interleaved mode. The order of samples is C0, ..., C0, C1, ..., C1, C2...
233 * The channel buffers lay in the DMA buffer continuously (see default copy
234 * handlers in the pcm_lib.c file).
235 *
236 * Here we increment the DMA buffer position every time we write a byte to any channel 'buffer'.
237 * We need this to simulate the correct hardware pointer moving.
238 */
fill_block_pattern_n(struct pcmtst_buf_iter * v_iter,struct snd_pcm_runtime * runtime)239 static void fill_block_pattern_n(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
240 {
241 size_t i;
242 unsigned int channels = runtime->channels;
243 short ch_num;
244
245 for (i = 0; i < v_iter->b_rw; i++) {
246 ch_num = i % channels;
247 runtime->dma_area[buf_pos_n(v_iter, channels, ch_num)] =
248 patt_bufs[ch_num].buf[(v_iter->total_bytes / channels)
249 % patt_bufs[ch_num].len];
250 inc_buf_pos(v_iter, 1, runtime->dma_bytes);
251 }
252 }
253
254 // Fill buffer in the interleaved mode. The order of samples is C0, C1, C2, C0, C1, C2, ...
fill_block_pattern_i(struct pcmtst_buf_iter * v_iter,struct snd_pcm_runtime * runtime)255 static void fill_block_pattern_i(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
256 {
257 size_t sample;
258 size_t pos_in_ch, pos_pattern;
259 short ch, pos_sample;
260
261 pos_in_ch = ch_pos_i(v_iter->total_bytes, runtime->channels, v_iter->sample_bytes);
262
263 for (sample = 0; sample < v_iter->s_rw_ch; sample++) {
264 for (ch = 0; ch < runtime->channels; ch++) {
265 for (pos_sample = 0; pos_sample < v_iter->sample_bytes; pos_sample++) {
266 pos_pattern = (pos_in_ch + sample * v_iter->sample_bytes
267 + pos_sample) % patt_bufs[ch].len;
268 runtime->dma_area[v_iter->buf_pos] = patt_bufs[ch].buf[pos_pattern];
269 inc_buf_pos(v_iter, 1, runtime->dma_bytes);
270 }
271 }
272 }
273 }
274
fill_block_pattern(struct pcmtst_buf_iter * v_iter,struct snd_pcm_runtime * runtime)275 static void fill_block_pattern(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
276 {
277 if (v_iter->interleaved)
278 fill_block_pattern_i(v_iter, runtime);
279 else
280 fill_block_pattern_n(v_iter, runtime);
281 }
282
fill_block_rand_n(struct pcmtst_buf_iter * v_iter,struct snd_pcm_runtime * runtime)283 static void fill_block_rand_n(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
284 {
285 unsigned int channels = runtime->channels;
286 // Remaining space in all channel buffers
287 size_t bytes_remain = runtime->dma_bytes - v_iter->buf_pos;
288 unsigned int i;
289
290 for (i = 0; i < channels; i++) {
291 if (v_iter->b_rw <= bytes_remain) {
292 //b_rw - count of bytes must be written for all channels at each timer tick
293 get_random_bytes(runtime->dma_area + buf_pos_n(v_iter, channels, i),
294 v_iter->b_rw / channels);
295 } else {
296 // Write to the end of buffer and start from the beginning of it
297 get_random_bytes(runtime->dma_area + buf_pos_n(v_iter, channels, i),
298 bytes_remain / channels);
299 get_random_bytes(runtime->dma_area + v_iter->chan_block * i,
300 (v_iter->b_rw - bytes_remain) / channels);
301 }
302 }
303 inc_buf_pos(v_iter, v_iter->b_rw, runtime->dma_bytes);
304 }
305
fill_block_rand_i(struct pcmtst_buf_iter * v_iter,struct snd_pcm_runtime * runtime)306 static void fill_block_rand_i(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
307 {
308 size_t in_cur_block = runtime->dma_bytes - v_iter->buf_pos;
309
310 if (v_iter->b_rw <= in_cur_block) {
311 get_random_bytes(&runtime->dma_area[v_iter->buf_pos], v_iter->b_rw);
312 } else {
313 get_random_bytes(&runtime->dma_area[v_iter->buf_pos], in_cur_block);
314 get_random_bytes(runtime->dma_area, v_iter->b_rw - in_cur_block);
315 }
316 inc_buf_pos(v_iter, v_iter->b_rw, runtime->dma_bytes);
317 }
318
fill_block_random(struct pcmtst_buf_iter * v_iter,struct snd_pcm_runtime * runtime)319 static void fill_block_random(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
320 {
321 if (v_iter->interleaved)
322 fill_block_rand_i(v_iter, runtime);
323 else
324 fill_block_rand_n(v_iter, runtime);
325 }
326
fill_block(struct pcmtst_buf_iter * v_iter,struct snd_pcm_runtime * runtime)327 static void fill_block(struct pcmtst_buf_iter *v_iter, struct snd_pcm_runtime *runtime)
328 {
329 switch (fill_mode) {
330 case FILL_MODE_RAND:
331 fill_block_random(v_iter, runtime);
332 break;
333 case FILL_MODE_PAT:
334 fill_block_pattern(v_iter, runtime);
335 break;
336 }
337 }
338
339 /*
340 * Here we iterate through the buffer by (buffer_size / iterates_per_second) bytes.
341 * The driver uses timer to simulate the hardware pointer moving, and notify the PCM middle layer
342 * about period elapsed.
343 */
timer_timeout(struct timer_list * data)344 static void timer_timeout(struct timer_list *data)
345 {
346 struct pcmtst_buf_iter *v_iter;
347 struct snd_pcm_substream *substream;
348
349 v_iter = timer_container_of(v_iter, data, timer_instance);
350 substream = v_iter->substream;
351
352 if (v_iter->suspend)
353 return;
354
355 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !v_iter->is_buf_corrupted)
356 check_buf_block(v_iter, substream->runtime);
357 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
358 fill_block(v_iter, substream->runtime);
359 else
360 inc_buf_pos(v_iter, v_iter->b_rw, substream->runtime->dma_bytes);
361
362 v_iter->period_pos += v_iter->b_rw;
363 if (v_iter->period_pos >= v_iter->period_bytes) {
364 v_iter->period_pos %= v_iter->period_bytes;
365 snd_pcm_period_elapsed(substream);
366 }
367
368 if (!v_iter->suspend)
369 mod_timer(&v_iter->timer_instance, jiffies + TIMER_INTERVAL + inject_delay);
370 }
371
snd_pcmtst_pcm_open(struct snd_pcm_substream * substream)372 static int snd_pcmtst_pcm_open(struct snd_pcm_substream *substream)
373 {
374 struct snd_pcm_runtime *runtime = substream->runtime;
375 struct pcmtst_buf_iter *v_iter;
376
377 if (inject_open_err)
378 return -EBUSY;
379
380 v_iter = kzalloc(sizeof(*v_iter), GFP_KERNEL);
381 if (!v_iter)
382 return -ENOMEM;
383
384 v_iter->substream = substream;
385 runtime->hw = snd_pcmtst_hw;
386 runtime->private_data = v_iter;
387
388 playback_capture_test = 0;
389 ioctl_reset_test = 0;
390
391 timer_setup(&v_iter->timer_instance, timer_timeout, 0);
392
393 return 0;
394 }
395
snd_pcmtst_pcm_close(struct snd_pcm_substream * substream)396 static int snd_pcmtst_pcm_close(struct snd_pcm_substream *substream)
397 {
398 struct pcmtst_buf_iter *v_iter = substream->runtime->private_data;
399
400 timer_shutdown_sync(&v_iter->timer_instance);
401 playback_capture_test = !v_iter->is_buf_corrupted;
402 kfree(v_iter);
403 return 0;
404 }
405
reset_buf_iterator(struct pcmtst_buf_iter * v_iter)406 static inline void reset_buf_iterator(struct pcmtst_buf_iter *v_iter)
407 {
408 v_iter->buf_pos = 0;
409 v_iter->is_buf_corrupted = false;
410 v_iter->period_pos = 0;
411 v_iter->total_bytes = 0;
412 }
413
start_pcmtest_timer(struct pcmtst_buf_iter * v_iter)414 static inline void start_pcmtest_timer(struct pcmtst_buf_iter *v_iter)
415 {
416 v_iter->suspend = false;
417 mod_timer(&v_iter->timer_instance, jiffies + TIMER_INTERVAL);
418 }
419
snd_pcmtst_pcm_trigger(struct snd_pcm_substream * substream,int cmd)420 static int snd_pcmtst_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
421 {
422 struct pcmtst_buf_iter *v_iter = substream->runtime->private_data;
423
424 if (inject_trigger_err)
425 return -EINVAL;
426 switch (cmd) {
427 case SNDRV_PCM_TRIGGER_START:
428 reset_buf_iterator(v_iter);
429 start_pcmtest_timer(v_iter);
430 break;
431 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
432 start_pcmtest_timer(v_iter);
433 break;
434 case SNDRV_PCM_TRIGGER_STOP:
435 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
436 // We can't call timer_shutdown_sync here, as it is forbidden to sleep here
437 v_iter->suspend = true;
438 timer_delete(&v_iter->timer_instance);
439 break;
440 }
441
442 return 0;
443 }
444
snd_pcmtst_pcm_pointer(struct snd_pcm_substream * substream)445 static snd_pcm_uframes_t snd_pcmtst_pcm_pointer(struct snd_pcm_substream *substream)
446 {
447 struct pcmtst_buf_iter *v_iter = substream->runtime->private_data;
448
449 return bytes_to_frames(substream->runtime, v_iter->buf_pos);
450 }
451
snd_pcmtst_free(struct pcmtst * pcmtst)452 static int snd_pcmtst_free(struct pcmtst *pcmtst)
453 {
454 if (!pcmtst)
455 return 0;
456 kfree(pcmtst);
457 return 0;
458 }
459
460 // These callbacks are required, but empty - all freeing occurs in pdev_remove
snd_pcmtst_dev_free(struct snd_device * device)461 static int snd_pcmtst_dev_free(struct snd_device *device)
462 {
463 return 0;
464 }
465
pcmtst_pdev_release(struct device * dev)466 static void pcmtst_pdev_release(struct device *dev)
467 {
468 }
469
snd_pcmtst_pcm_prepare(struct snd_pcm_substream * substream)470 static int snd_pcmtst_pcm_prepare(struct snd_pcm_substream *substream)
471 {
472 struct snd_pcm_runtime *runtime = substream->runtime;
473 struct pcmtst_buf_iter *v_iter = runtime->private_data;
474
475 if (inject_prepare_err)
476 return -EINVAL;
477
478 v_iter->sample_bytes = samples_to_bytes(runtime, 1);
479 v_iter->period_bytes = snd_pcm_lib_period_bytes(substream);
480 v_iter->interleaved = true;
481 if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ||
482 runtime->access == SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED) {
483 v_iter->chan_block = snd_pcm_lib_buffer_bytes(substream) / runtime->channels;
484 v_iter->interleaved = false;
485 }
486 // We want to record RATE * ch_cnt samples per sec, it is rate * sample_bytes * ch_cnt bytes
487 v_iter->s_rw_ch = runtime->rate / TIMER_PER_SEC;
488 v_iter->b_rw = v_iter->s_rw_ch * v_iter->sample_bytes * runtime->channels;
489
490 return 0;
491 }
492
snd_pcmtst_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)493 static int snd_pcmtst_pcm_hw_params(struct snd_pcm_substream *substream,
494 struct snd_pcm_hw_params *params)
495 {
496 if (inject_hwpars_err)
497 return -EBUSY;
498 return 0;
499 }
500
snd_pcmtst_pcm_hw_free(struct snd_pcm_substream * substream)501 static int snd_pcmtst_pcm_hw_free(struct snd_pcm_substream *substream)
502 {
503 return 0;
504 }
505
snd_pcmtst_ioctl(struct snd_pcm_substream * substream,unsigned int cmd,void * arg)506 static int snd_pcmtst_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg)
507 {
508 switch (cmd) {
509 case SNDRV_PCM_IOCTL1_RESET:
510 ioctl_reset_test = 1;
511 break;
512 }
513 return snd_pcm_lib_ioctl(substream, cmd, arg);
514 }
515
snd_pcmtst_sync_stop(struct snd_pcm_substream * substream)516 static int snd_pcmtst_sync_stop(struct snd_pcm_substream *substream)
517 {
518 struct pcmtst_buf_iter *v_iter = substream->runtime->private_data;
519
520 timer_delete_sync(&v_iter->timer_instance);
521
522 return 0;
523 }
524
525 static const struct snd_pcm_ops snd_pcmtst_playback_ops = {
526 .open = snd_pcmtst_pcm_open,
527 .close = snd_pcmtst_pcm_close,
528 .trigger = snd_pcmtst_pcm_trigger,
529 .hw_params = snd_pcmtst_pcm_hw_params,
530 .ioctl = snd_pcmtst_ioctl,
531 .sync_stop = snd_pcmtst_sync_stop,
532 .hw_free = snd_pcmtst_pcm_hw_free,
533 .prepare = snd_pcmtst_pcm_prepare,
534 .pointer = snd_pcmtst_pcm_pointer,
535 };
536
537 static const struct snd_pcm_ops snd_pcmtst_capture_ops = {
538 .open = snd_pcmtst_pcm_open,
539 .close = snd_pcmtst_pcm_close,
540 .trigger = snd_pcmtst_pcm_trigger,
541 .hw_params = snd_pcmtst_pcm_hw_params,
542 .hw_free = snd_pcmtst_pcm_hw_free,
543 .ioctl = snd_pcmtst_ioctl,
544 .sync_stop = snd_pcmtst_sync_stop,
545 .prepare = snd_pcmtst_pcm_prepare,
546 .pointer = snd_pcmtst_pcm_pointer,
547 };
548
snd_pcmtst_new_pcm(struct pcmtst * pcmtst)549 static int snd_pcmtst_new_pcm(struct pcmtst *pcmtst)
550 {
551 struct snd_pcm *pcm;
552 int err;
553
554 err = snd_pcm_new(pcmtst->card, "PCMTest", 0, PLAYBACK_SUBSTREAM_CNT,
555 CAPTURE_SUBSTREAM_CNT, &pcm);
556 if (err < 0)
557 return err;
558 pcm->private_data = pcmtst;
559 strscpy(pcm->name, "PCMTest");
560 pcmtst->pcm = pcm;
561 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_pcmtst_playback_ops);
562 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_pcmtst_capture_ops);
563
564 err = snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &pcmtst->pdev->dev,
565 0, 128 * 1024);
566 return err;
567 }
568
snd_pcmtst_create(struct snd_card * card,struct platform_device * pdev,struct pcmtst ** r_pcmtst)569 static int snd_pcmtst_create(struct snd_card *card, struct platform_device *pdev,
570 struct pcmtst **r_pcmtst)
571 {
572 struct pcmtst *pcmtst;
573 int err;
574 static const struct snd_device_ops ops = {
575 .dev_free = snd_pcmtst_dev_free,
576 };
577
578 pcmtst = kzalloc(sizeof(*pcmtst), GFP_KERNEL);
579 if (!pcmtst)
580 return -ENOMEM;
581 pcmtst->card = card;
582 pcmtst->pdev = pdev;
583
584 err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, pcmtst, &ops);
585 if (err < 0)
586 goto _err_free_chip;
587
588 err = snd_pcmtst_new_pcm(pcmtst);
589 if (err < 0)
590 goto _err_free_chip;
591
592 *r_pcmtst = pcmtst;
593 return 0;
594
595 _err_free_chip:
596 snd_pcmtst_free(pcmtst);
597 return err;
598 }
599
pcmtst_probe(struct platform_device * pdev)600 static int pcmtst_probe(struct platform_device *pdev)
601 {
602 struct snd_card *card;
603 struct pcmtst *pcmtst;
604 int err;
605
606 err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
607 if (err)
608 return err;
609
610 err = snd_devm_card_new(&pdev->dev, index, id, THIS_MODULE, 0, &card);
611 if (err < 0)
612 return err;
613 err = snd_pcmtst_create(card, pdev, &pcmtst);
614 if (err < 0)
615 return err;
616
617 strscpy(card->driver, "PCM-TEST Driver");
618 strscpy(card->shortname, "PCM-Test");
619 strscpy(card->longname, "PCM-Test virtual driver");
620
621 err = snd_card_register(card);
622 if (err < 0)
623 return err;
624
625 platform_set_drvdata(pdev, pcmtst);
626
627 return 0;
628 }
629
pdev_remove(struct platform_device * pdev)630 static void pdev_remove(struct platform_device *pdev)
631 {
632 struct pcmtst *pcmtst = platform_get_drvdata(pdev);
633
634 snd_pcmtst_free(pcmtst);
635 }
636
637 static struct platform_device pcmtst_pdev = {
638 .name = "pcmtest",
639 .dev.release = pcmtst_pdev_release,
640 };
641
642 static struct platform_driver pcmtst_pdrv = {
643 .probe = pcmtst_probe,
644 .remove = pdev_remove,
645 .driver = {
646 .name = "pcmtest",
647 },
648 };
649
pattern_write(struct file * file,const char __user * u_buff,size_t len,loff_t * off)650 static ssize_t pattern_write(struct file *file, const char __user *u_buff, size_t len, loff_t *off)
651 {
652 struct pattern_buf *patt_buf = file->f_inode->i_private;
653 ssize_t to_write = len;
654
655 if (*off + to_write > MAX_PATTERN_LEN)
656 to_write = MAX_PATTERN_LEN - *off;
657
658 // Crop silently everything over the buffer
659 if (to_write <= 0)
660 return len;
661
662 if (copy_from_user(patt_buf->buf + *off, u_buff, to_write))
663 return -EFAULT;
664
665 patt_buf->len = *off + to_write;
666 *off += to_write;
667
668 return to_write;
669 }
670
pattern_read(struct file * file,char __user * u_buff,size_t len,loff_t * off)671 static ssize_t pattern_read(struct file *file, char __user *u_buff, size_t len, loff_t *off)
672 {
673 struct pattern_buf *patt_buf = file->f_inode->i_private;
674 ssize_t to_read = len;
675
676 if (*off + to_read >= MAX_PATTERN_LEN)
677 to_read = MAX_PATTERN_LEN - *off;
678 if (to_read <= 0)
679 return 0;
680
681 if (copy_to_user(u_buff, patt_buf->buf + *off, to_read))
682 to_read = 0;
683 else
684 *off += to_read;
685
686 return to_read;
687 }
688
689 static const struct file_operations fill_pattern_fops = {
690 .read = pattern_read,
691 .write = pattern_write,
692 };
693
setup_patt_bufs(void)694 static int setup_patt_bufs(void)
695 {
696 size_t i;
697
698 for (i = 0; i < ARRAY_SIZE(patt_bufs); i++) {
699 patt_bufs[i].buf = kzalloc(MAX_PATTERN_LEN, GFP_KERNEL);
700 if (!patt_bufs[i].buf)
701 break;
702 strcpy(patt_bufs[i].buf, DEFAULT_PATTERN);
703 patt_bufs[i].len = DEFAULT_PATTERN_LEN;
704 }
705
706 return i;
707 }
708
709 static const char * const pattern_files[] = { "fill_pattern0", "fill_pattern1",
710 "fill_pattern2", "fill_pattern3"};
init_debug_files(int buf_count)711 static int init_debug_files(int buf_count)
712 {
713 size_t i;
714 char len_file_name[32];
715
716 driver_debug_dir = debugfs_create_dir("pcmtest", NULL);
717 if (IS_ERR(driver_debug_dir))
718 return PTR_ERR(driver_debug_dir);
719 debugfs_create_u8("pc_test", 0444, driver_debug_dir, &playback_capture_test);
720 debugfs_create_u8("ioctl_test", 0444, driver_debug_dir, &ioctl_reset_test);
721
722 for (i = 0; i < buf_count; i++) {
723 debugfs_create_file(pattern_files[i], 0600, driver_debug_dir,
724 &patt_bufs[i], &fill_pattern_fops);
725 snprintf(len_file_name, sizeof(len_file_name), "%s_len", pattern_files[i]);
726 debugfs_create_u32(len_file_name, 0444, driver_debug_dir, &patt_bufs[i].len);
727 }
728
729 return 0;
730 }
731
free_pattern_buffers(void)732 static void free_pattern_buffers(void)
733 {
734 int i;
735
736 for (i = 0; i < buf_allocated; i++)
737 kfree(patt_bufs[i].buf);
738 }
739
clear_debug_files(void)740 static void clear_debug_files(void)
741 {
742 debugfs_remove_recursive(driver_debug_dir);
743 }
744
mod_init(void)745 static int __init mod_init(void)
746 {
747 int err = 0;
748
749 buf_allocated = setup_patt_bufs();
750 if (!buf_allocated)
751 return -ENOMEM;
752
753 snd_pcmtst_hw.channels_max = buf_allocated;
754
755 err = init_debug_files(buf_allocated);
756 if (err)
757 return err;
758 err = platform_device_register(&pcmtst_pdev);
759 if (err)
760 return err;
761 err = platform_driver_register(&pcmtst_pdrv);
762 if (err)
763 platform_device_unregister(&pcmtst_pdev);
764 return err;
765 }
766
mod_exit(void)767 static void __exit mod_exit(void)
768 {
769 clear_debug_files();
770 free_pattern_buffers();
771
772 platform_driver_unregister(&pcmtst_pdrv);
773 platform_device_unregister(&pcmtst_pdev);
774 }
775
776 MODULE_DESCRIPTION("Virtual ALSA driver for PCM testing/fuzzing");
777 MODULE_LICENSE("GPL");
778 MODULE_AUTHOR("Ivan Orlov");
779 module_init(mod_init);
780 module_exit(mod_exit);
781