Lines Matching +full:non +full:- +full:interleaved
1 // SPDX-License-Identifier: GPL-2.0
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
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
23 * pattern to each separate channel. For example, if we have 2 channels, format = U8, interleaved
25 * each channel will contain abacabaabacaba... Same for the non-interleaved mode.
37 #include <linux/dma-mapping.h>
59 static int index = -1;
101 size_t period_pos; // period-relative position
107 bool interleaved; // Interleaved/Non-interleaved mode member
109 size_t chan_block; // Bytes in one channel buffer when non-interleaved
144 v_iter->total_bytes += by; in inc_buf_pos()
145 v_iter->buf_pos += by; in inc_buf_pos()
146 if (v_iter->buf_pos >= bytes) in inc_buf_pos()
147 v_iter->buf_pos %= bytes; in inc_buf_pos()
151 * Position in the DMA buffer when we are in the non-interleaved mode. We increment buf_pos
158 return v_iter->buf_pos / channels + v_iter->chan_block * chan_num; in buf_pos_n()
162 * Get the count of bytes written for the current channel in the interleaved mode.
177 for (i = 0; i < v_iter->b_rw; i++) { in check_buf_block_i()
178 current_byte = runtime->dma_area[v_iter->buf_pos]; in check_buf_block_i()
181 ch_num = (v_iter->total_bytes / v_iter->sample_bytes) % runtime->channels; in check_buf_block_i()
182 if (current_byte != patt_bufs[ch_num].buf[ch_pos_i(v_iter->total_bytes, in check_buf_block_i()
183 runtime->channels, in check_buf_block_i()
184 v_iter->sample_bytes) in check_buf_block_i()
186 v_iter->is_buf_corrupted = true; in check_buf_block_i()
189 inc_buf_pos(v_iter, 1, runtime->dma_bytes); in check_buf_block_i()
192 inc_buf_pos(v_iter, v_iter->b_rw - i, runtime->dma_bytes); in check_buf_block_i()
197 unsigned int channels = runtime->channels; in check_buf_block_ni()
202 for (i = 0; i < v_iter->b_rw; i++) { in check_buf_block_ni()
204 current_byte = runtime->dma_area[buf_pos_n(v_iter, channels, ch_num)]; in check_buf_block_ni()
207 if (current_byte != patt_bufs[ch_num].buf[(v_iter->total_bytes / channels) in check_buf_block_ni()
209 v_iter->is_buf_corrupted = true; in check_buf_block_ni()
212 inc_buf_pos(v_iter, 1, runtime->dma_bytes); in check_buf_block_ni()
214 inc_buf_pos(v_iter, v_iter->b_rw - i, runtime->dma_bytes); in check_buf_block_ni()
224 if (v_iter->interleaved) in check_buf_block()
231 * Fill buffer in the non-interleaved mode. The order of samples is C0, ..., C0, C1, ..., C1, C2...
241 unsigned int channels = runtime->channels; in fill_block_pattern_n()
244 for (i = 0; i < v_iter->b_rw; i++) { in fill_block_pattern_n()
246 runtime->dma_area[buf_pos_n(v_iter, channels, ch_num)] = in fill_block_pattern_n()
247 patt_bufs[ch_num].buf[(v_iter->total_bytes / channels) in fill_block_pattern_n()
249 inc_buf_pos(v_iter, 1, runtime->dma_bytes); in fill_block_pattern_n()
253 // Fill buffer in the interleaved mode. The order of samples is C0, C1, C2, C0, C1, C2, ...
260 pos_in_ch = ch_pos_i(v_iter->total_bytes, runtime->channels, v_iter->sample_bytes); in fill_block_pattern_i()
262 for (sample = 0; sample < v_iter->s_rw_ch; sample++) { in fill_block_pattern_i()
263 for (ch = 0; ch < runtime->channels; ch++) { in fill_block_pattern_i()
264 for (pos_sample = 0; pos_sample < v_iter->sample_bytes; pos_sample++) { in fill_block_pattern_i()
265 pos_pattern = (pos_in_ch + sample * v_iter->sample_bytes in fill_block_pattern_i()
267 runtime->dma_area[v_iter->buf_pos] = patt_bufs[ch].buf[pos_pattern]; in fill_block_pattern_i()
268 inc_buf_pos(v_iter, 1, runtime->dma_bytes); in fill_block_pattern_i()
276 if (v_iter->interleaved) in fill_block_pattern()
284 unsigned int channels = runtime->channels; in fill_block_rand_n()
286 size_t bytes_remain = runtime->dma_bytes - v_iter->buf_pos; in fill_block_rand_n()
290 if (v_iter->b_rw <= bytes_remain) { in fill_block_rand_n()
291 //b_rw - count of bytes must be written for all channels at each timer tick in fill_block_rand_n()
292 get_random_bytes(runtime->dma_area + buf_pos_n(v_iter, channels, i), in fill_block_rand_n()
293 v_iter->b_rw / channels); in fill_block_rand_n()
296 get_random_bytes(runtime->dma_area + buf_pos_n(v_iter, channels, i), in fill_block_rand_n()
298 get_random_bytes(runtime->dma_area + v_iter->chan_block * i, in fill_block_rand_n()
299 (v_iter->b_rw - bytes_remain) / channels); in fill_block_rand_n()
302 inc_buf_pos(v_iter, v_iter->b_rw, runtime->dma_bytes); in fill_block_rand_n()
307 size_t in_cur_block = runtime->dma_bytes - v_iter->buf_pos; in fill_block_rand_i()
309 if (v_iter->b_rw <= in_cur_block) { in fill_block_rand_i()
310 get_random_bytes(&runtime->dma_area[v_iter->buf_pos], v_iter->b_rw); in fill_block_rand_i()
312 get_random_bytes(&runtime->dma_area[v_iter->buf_pos], in_cur_block); in fill_block_rand_i()
313 get_random_bytes(runtime->dma_area, v_iter->b_rw - in_cur_block); in fill_block_rand_i()
315 inc_buf_pos(v_iter, v_iter->b_rw, runtime->dma_bytes); in fill_block_rand_i()
320 if (v_iter->interleaved) in fill_block_random()
349 substream = v_iter->substream; in timer_timeout()
351 if (v_iter->suspend) in timer_timeout()
354 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !v_iter->is_buf_corrupted) in timer_timeout()
355 check_buf_block(v_iter, substream->runtime); in timer_timeout()
356 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) in timer_timeout()
357 fill_block(v_iter, substream->runtime); in timer_timeout()
359 inc_buf_pos(v_iter, v_iter->b_rw, substream->runtime->dma_bytes); in timer_timeout()
361 v_iter->period_pos += v_iter->b_rw; in timer_timeout()
362 if (v_iter->period_pos >= v_iter->period_bytes) { in timer_timeout()
363 v_iter->period_pos %= v_iter->period_bytes; in timer_timeout()
367 if (!v_iter->suspend) in timer_timeout()
368 mod_timer(&v_iter->timer_instance, jiffies + TIMER_INTERVAL + inject_delay); in timer_timeout()
373 struct snd_pcm_runtime *runtime = substream->runtime; in snd_pcmtst_pcm_open()
377 return -EBUSY; in snd_pcmtst_pcm_open()
381 return -ENOMEM; in snd_pcmtst_pcm_open()
383 v_iter->substream = substream; in snd_pcmtst_pcm_open()
384 runtime->hw = snd_pcmtst_hw; in snd_pcmtst_pcm_open()
385 runtime->private_data = v_iter; in snd_pcmtst_pcm_open()
390 timer_setup(&v_iter->timer_instance, timer_timeout, 0); in snd_pcmtst_pcm_open()
397 struct pcmtst_buf_iter *v_iter = substream->runtime->private_data; in snd_pcmtst_pcm_close()
399 timer_shutdown_sync(&v_iter->timer_instance); in snd_pcmtst_pcm_close()
400 playback_capture_test = !v_iter->is_buf_corrupted; in snd_pcmtst_pcm_close()
407 v_iter->buf_pos = 0; in reset_buf_iterator()
408 v_iter->is_buf_corrupted = false; in reset_buf_iterator()
409 v_iter->period_pos = 0; in reset_buf_iterator()
410 v_iter->total_bytes = 0; in reset_buf_iterator()
415 v_iter->suspend = false; in start_pcmtest_timer()
416 mod_timer(&v_iter->timer_instance, jiffies + TIMER_INTERVAL); in start_pcmtest_timer()
421 struct pcmtst_buf_iter *v_iter = substream->runtime->private_data; in snd_pcmtst_pcm_trigger()
424 return -EINVAL; in snd_pcmtst_pcm_trigger()
436 v_iter->suspend = true; in snd_pcmtst_pcm_trigger()
437 timer_delete(&v_iter->timer_instance); in snd_pcmtst_pcm_trigger()
446 struct pcmtst_buf_iter *v_iter = substream->runtime->private_data; in snd_pcmtst_pcm_pointer()
448 return bytes_to_frames(substream->runtime, v_iter->buf_pos); in snd_pcmtst_pcm_pointer()
459 // These callbacks are required, but empty - all freeing occurs in pdev_remove
471 struct snd_pcm_runtime *runtime = substream->runtime; in snd_pcmtst_pcm_prepare()
472 struct pcmtst_buf_iter *v_iter = runtime->private_data; in snd_pcmtst_pcm_prepare()
475 return -EINVAL; in snd_pcmtst_pcm_prepare()
477 v_iter->sample_bytes = samples_to_bytes(runtime, 1); in snd_pcmtst_pcm_prepare()
478 v_iter->period_bytes = snd_pcm_lib_period_bytes(substream); in snd_pcmtst_pcm_prepare()
479 v_iter->interleaved = true; in snd_pcmtst_pcm_prepare()
480 if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED || in snd_pcmtst_pcm_prepare()
481 runtime->access == SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED) { in snd_pcmtst_pcm_prepare()
482 v_iter->chan_block = snd_pcm_lib_buffer_bytes(substream) / runtime->channels; in snd_pcmtst_pcm_prepare()
483 v_iter->interleaved = false; in snd_pcmtst_pcm_prepare()
486 v_iter->s_rw_ch = runtime->rate / TIMER_PER_SEC; in snd_pcmtst_pcm_prepare()
487 v_iter->b_rw = v_iter->s_rw_ch * v_iter->sample_bytes * runtime->channels; in snd_pcmtst_pcm_prepare()
496 return -EBUSY; in snd_pcmtst_pcm_hw_params()
517 struct pcmtst_buf_iter *v_iter = substream->runtime->private_data; in snd_pcmtst_sync_stop()
519 timer_delete_sync(&v_iter->timer_instance); in snd_pcmtst_sync_stop()
553 err = snd_pcm_new(pcmtst->card, "PCMTest", 0, PLAYBACK_SUBSTREAM_CNT, in snd_pcmtst_new_pcm()
557 pcm->private_data = pcmtst; in snd_pcmtst_new_pcm()
558 strcpy(pcm->name, "PCMTest"); in snd_pcmtst_new_pcm()
559 pcmtst->pcm = pcm; in snd_pcmtst_new_pcm()
563 err = snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &pcmtst->pdev->dev, in snd_pcmtst_new_pcm()
579 return -ENOMEM; in snd_pcmtst_create()
580 pcmtst->card = card; in snd_pcmtst_create()
581 pcmtst->pdev = pdev; in snd_pcmtst_create()
605 err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); in pcmtst_probe()
609 err = snd_devm_card_new(&pdev->dev, index, id, THIS_MODULE, 0, &card); in pcmtst_probe()
616 strcpy(card->driver, "PCM-TEST Driver"); in pcmtst_probe()
617 strcpy(card->shortname, "PCM-Test"); in pcmtst_probe()
618 strcpy(card->longname, "PCM-Test virtual driver"); in pcmtst_probe()
651 struct pattern_buf *patt_buf = file->f_inode->i_private; in pattern_write()
655 to_write = MAX_PATTERN_LEN - *off; in pattern_write()
661 if (copy_from_user(patt_buf->buf + *off, u_buff, to_write)) in pattern_write()
662 return -EFAULT; in pattern_write()
664 patt_buf->len = *off + to_write; in pattern_write()
672 struct pattern_buf *patt_buf = file->f_inode->i_private; in pattern_read()
676 to_read = MAX_PATTERN_LEN - *off; in pattern_read()
680 if (copy_to_user(u_buff, patt_buf->buf + *off, to_read)) in pattern_read()
750 return -ENOMEM; in mod_init()