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