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
59static int index = -1;
60static char *id = "pcmtest";
61static bool enable = true;
62static int inject_delay;
63static bool inject_hwpars_err;
64static bool inject_prepare_err;
65static bool inject_trigger_err;
66static bool inject_open_err;
67
68static short fill_mode = FILL_MODE_PAT;
69
70static u8 playback_capture_test;
71static u8 ioctl_reset_test;
72static struct dentry *driver_debug_dir;
73
74module_param(index, int, 0444);
75MODULE_PARM_DESC(index, "Index value for pcmtest soundcard");
76module_param(id, charp, 0444);
77MODULE_PARM_DESC(id, "ID string for pcmtest soundcard");
78module_param(enable, bool, 0444);
79MODULE_PARM_DESC(enable, "Enable pcmtest soundcard.");
80module_param(fill_mode, short, 0600);
81MODULE_PARM_DESC(fill_mode, "Buffer fill mode: rand(0) or pattern(1)");
82module_param(inject_delay, int, 0600);
83MODULE_PARM_DESC(inject_delay, "Inject delays during playback/capture (in jiffies)");
84module_param(inject_hwpars_err, bool, 0600);
85MODULE_PARM_DESC(inject_hwpars_err, "Inject EBUSY error in the 'hw_params' callback");
86module_param(inject_prepare_err, bool, 0600);
87MODULE_PARM_DESC(inject_prepare_err, "Inject EINVAL error in the 'prepare' callback");
88module_param(inject_trigger_err, bool, 0600);
89MODULE_PARM_DESC(inject_trigger_err, "Inject EINVAL error in the 'trigger' callback");
90module_param(inject_open_err, bool, 0600);
91MODULE_PARM_DESC(inject_open_err, "Inject EBUSY error in the 'open' callback");
92
93struct pcmtst {
94	struct snd_pcm *pcm;
95	struct snd_card *card;
96	struct platform_device *pdev;
97};
98
99struct 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
115static 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
134struct pattern_buf {
135	char *buf;
136	u32 len;
137};
138
139static int buf_allocated;
140static struct pattern_buf patt_bufs[MAX_CHANNELS_NUM];
141
142static 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 */
155static 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 */
166static 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
171static 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
195static 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 */
222static 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 */
238static 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, ...
254static 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
274static 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
282static 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
305static 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
318static 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
326static 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 */
343static 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
371static 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
395static 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
405static 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
413static 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
419static 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
444static 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
451static 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
460static int snd_pcmtst_dev_free(struct snd_device *device)
461{
462	return 0;
463}
464
465static void pcmtst_pdev_release(struct device *dev)
466{
467}
468
469static 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
492static 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
500static int snd_pcmtst_pcm_hw_free(struct snd_pcm_substream *substream)
501{
502	return 0;
503}
504
505static 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
515static 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
524static 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
536static 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
548static 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
568static 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
599static 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
629static void pdev_remove(struct platform_device *pdev)
630{
631	struct pcmtst *pcmtst = platform_get_drvdata(pdev);
632
633	snd_pcmtst_free(pcmtst);
634}
635
636static struct platform_device pcmtst_pdev = {
637	.name =		"pcmtest",
638	.dev.release =	pcmtst_pdev_release,
639};
640
641static struct platform_driver pcmtst_pdrv = {
642	.probe =	pcmtst_probe,
643	.remove_new =	pdev_remove,
644	.driver =	{
645		.name = "pcmtest",
646	},
647};
648
649static 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
670static 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
688static const struct file_operations fill_pattern_fops = {
689	.read = pattern_read,
690	.write = pattern_write,
691};
692
693static 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
708static const char * const pattern_files[] = { "fill_pattern0", "fill_pattern1",
709					      "fill_pattern2", "fill_pattern3"};
710static 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
731static 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
739static void clear_debug_files(void)
740{
741	debugfs_remove_recursive(driver_debug_dir);
742}
743
744static 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
766static 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
775MODULE_LICENSE("GPL");
776MODULE_AUTHOR("Ivan Orlov");
777module_init(mod_init);
778module_exit(mod_exit);
779