1c72fcc34Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
2c72fcc34Sopenharmony_ci//
3c72fcc34Sopenharmony_ci// allocator.h - a header of a generator for test with buffers of PCM frames.
4c72fcc34Sopenharmony_ci//
5c72fcc34Sopenharmony_ci// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
6c72fcc34Sopenharmony_ci//
7c72fcc34Sopenharmony_ci// Licensed under the terms of the GNU General Public License, version 2.
8c72fcc34Sopenharmony_ci
9c72fcc34Sopenharmony_ci#include "generator.h"
10c72fcc34Sopenharmony_ci
11c72fcc34Sopenharmony_ci#include <stdlib.h>
12c72fcc34Sopenharmony_ci
13c72fcc34Sopenharmony_ci#include <sys/types.h>
14c72fcc34Sopenharmony_ci#include <sys/stat.h>
15c72fcc34Sopenharmony_ci#include <fcntl.h>
16c72fcc34Sopenharmony_ci
17c72fcc34Sopenharmony_ci#include <unistd.h>
18c72fcc34Sopenharmony_ci
19c72fcc34Sopenharmony_ciint generator_context_init(struct test_generator *gen,
20c72fcc34Sopenharmony_ci			   uint64_t access_mask, uint64_t sample_format_mask,
21c72fcc34Sopenharmony_ci			   unsigned int min_samples_per_frame,
22c72fcc34Sopenharmony_ci			   unsigned int max_samples_per_frame,
23c72fcc34Sopenharmony_ci			   unsigned int min_frame_count,
24c72fcc34Sopenharmony_ci			   unsigned int max_frame_count,
25c72fcc34Sopenharmony_ci			   unsigned int step_frame_count,
26c72fcc34Sopenharmony_ci			   unsigned int private_size)
27c72fcc34Sopenharmony_ci{
28c72fcc34Sopenharmony_ci	gen->fd = open("/dev/urandom", O_RDONLY);
29c72fcc34Sopenharmony_ci	if (gen->fd < 0)
30c72fcc34Sopenharmony_ci		return -errno;
31c72fcc34Sopenharmony_ci
32c72fcc34Sopenharmony_ci	gen->private_data = malloc(private_size);
33c72fcc34Sopenharmony_ci	if (gen->private_data == NULL)
34c72fcc34Sopenharmony_ci		return -ENOMEM;
35c72fcc34Sopenharmony_ci	memset(gen->private_data, 0, private_size);
36c72fcc34Sopenharmony_ci
37c72fcc34Sopenharmony_ci	gen->access_mask = access_mask;
38c72fcc34Sopenharmony_ci	gen->sample_format_mask = sample_format_mask;
39c72fcc34Sopenharmony_ci	gen->min_samples_per_frame = min_samples_per_frame;
40c72fcc34Sopenharmony_ci	gen->max_samples_per_frame = max_samples_per_frame;
41c72fcc34Sopenharmony_ci	gen->min_frame_count = min_frame_count;
42c72fcc34Sopenharmony_ci	gen->max_frame_count = max_frame_count;
43c72fcc34Sopenharmony_ci	gen->step_frame_count = step_frame_count;
44c72fcc34Sopenharmony_ci
45c72fcc34Sopenharmony_ci	return 0;
46c72fcc34Sopenharmony_ci}
47c72fcc34Sopenharmony_ci
48c72fcc34Sopenharmony_cistatic void *allocate_buf(snd_pcm_access_t access,
49c72fcc34Sopenharmony_ci			  snd_pcm_format_t sample_format,
50c72fcc34Sopenharmony_ci			  unsigned int samples_per_frame,
51c72fcc34Sopenharmony_ci			  unsigned int frame_count)
52c72fcc34Sopenharmony_ci{
53c72fcc34Sopenharmony_ci	unsigned int bytes_per_sample;
54c72fcc34Sopenharmony_ci
55c72fcc34Sopenharmony_ci	bytes_per_sample = snd_pcm_format_physical_width(sample_format) / 8;
56c72fcc34Sopenharmony_ci
57c72fcc34Sopenharmony_ci	return calloc(samples_per_frame * frame_count, bytes_per_sample);
58c72fcc34Sopenharmony_ci}
59c72fcc34Sopenharmony_ci
60c72fcc34Sopenharmony_cistatic void *allocate_vector(snd_pcm_access_t access,
61c72fcc34Sopenharmony_ci			     snd_pcm_format_t sample_format,
62c72fcc34Sopenharmony_ci			     unsigned int samples_per_frame,
63c72fcc34Sopenharmony_ci			     unsigned int frame_count)
64c72fcc34Sopenharmony_ci{
65c72fcc34Sopenharmony_ci	unsigned int bytes_per_sample;
66c72fcc34Sopenharmony_ci	char **bufs;
67c72fcc34Sopenharmony_ci	int i;
68c72fcc34Sopenharmony_ci
69c72fcc34Sopenharmony_ci	bytes_per_sample = snd_pcm_format_physical_width(sample_format) / 8;
70c72fcc34Sopenharmony_ci
71c72fcc34Sopenharmony_ci	bufs = calloc(samples_per_frame, sizeof(char *));
72c72fcc34Sopenharmony_ci	if (bufs == NULL)
73c72fcc34Sopenharmony_ci		return NULL;
74c72fcc34Sopenharmony_ci
75c72fcc34Sopenharmony_ci	for (i = 0; i < samples_per_frame; ++i) {
76c72fcc34Sopenharmony_ci		bufs[i] = calloc(frame_count, bytes_per_sample);
77c72fcc34Sopenharmony_ci		if (bufs[i] == NULL) {
78c72fcc34Sopenharmony_ci			for (; i >= 0; --i)
79c72fcc34Sopenharmony_ci				free(bufs[i]);
80c72fcc34Sopenharmony_ci			free(bufs);
81c72fcc34Sopenharmony_ci			return NULL;
82c72fcc34Sopenharmony_ci		}
83c72fcc34Sopenharmony_ci	}
84c72fcc34Sopenharmony_ci
85c72fcc34Sopenharmony_ci	return bufs;
86c72fcc34Sopenharmony_ci}
87c72fcc34Sopenharmony_ci
88c72fcc34Sopenharmony_cistatic int fill_buf(int fd, void *frame_buffer, snd_pcm_access_t access,
89c72fcc34Sopenharmony_ci		    snd_pcm_format_t sample_format,
90c72fcc34Sopenharmony_ci		    unsigned int samples_per_frame, unsigned int frame_count)
91c72fcc34Sopenharmony_ci{
92c72fcc34Sopenharmony_ci	unsigned int size;
93c72fcc34Sopenharmony_ci	int len;
94c72fcc34Sopenharmony_ci
95c72fcc34Sopenharmony_ci	size = snd_pcm_format_physical_width(sample_format) / 8 *
96c72fcc34Sopenharmony_ci						samples_per_frame * frame_count;
97c72fcc34Sopenharmony_ci	while (size > 0) {
98c72fcc34Sopenharmony_ci		len = read(fd, frame_buffer, size);
99c72fcc34Sopenharmony_ci		if (len < 0)
100c72fcc34Sopenharmony_ci			return len;
101c72fcc34Sopenharmony_ci		size -= len;
102c72fcc34Sopenharmony_ci	}
103c72fcc34Sopenharmony_ci
104c72fcc34Sopenharmony_ci	return 0;
105c72fcc34Sopenharmony_ci}
106c72fcc34Sopenharmony_ci
107c72fcc34Sopenharmony_cistatic int fill_vector(int fd, void *frame_buffer, snd_pcm_access_t access,
108c72fcc34Sopenharmony_ci		       snd_pcm_format_t sample_format,
109c72fcc34Sopenharmony_ci		       unsigned int samples_per_frame, unsigned int frame_count)
110c72fcc34Sopenharmony_ci{
111c72fcc34Sopenharmony_ci	char **bufs = frame_buffer;
112c72fcc34Sopenharmony_ci	unsigned int size;
113c72fcc34Sopenharmony_ci	int len;
114c72fcc34Sopenharmony_ci	int i;
115c72fcc34Sopenharmony_ci
116c72fcc34Sopenharmony_ci	for (i = 0; i < samples_per_frame; ++i) {
117c72fcc34Sopenharmony_ci		size = frame_count *
118c72fcc34Sopenharmony_ci			snd_pcm_format_physical_width(sample_format) / 8;
119c72fcc34Sopenharmony_ci
120c72fcc34Sopenharmony_ci		while (size > 0) {
121c72fcc34Sopenharmony_ci			len = read(fd, bufs[i], size);
122c72fcc34Sopenharmony_ci			if (len < 0)
123c72fcc34Sopenharmony_ci				return len;
124c72fcc34Sopenharmony_ci			size -= len;
125c72fcc34Sopenharmony_ci		}
126c72fcc34Sopenharmony_ci	}
127c72fcc34Sopenharmony_ci
128c72fcc34Sopenharmony_ci	return 0;
129c72fcc34Sopenharmony_ci}
130c72fcc34Sopenharmony_ci
131c72fcc34Sopenharmony_cistatic void deallocate_buf(void *frame_buffer, unsigned int samples_per_frame)
132c72fcc34Sopenharmony_ci{
133c72fcc34Sopenharmony_ci	free(frame_buffer);
134c72fcc34Sopenharmony_ci}
135c72fcc34Sopenharmony_ci
136c72fcc34Sopenharmony_cistatic void deallocate_vector(void *frame_buffer,
137c72fcc34Sopenharmony_ci			      unsigned int samples_per_frame)
138c72fcc34Sopenharmony_ci{
139c72fcc34Sopenharmony_ci	char **bufs = frame_buffer;
140c72fcc34Sopenharmony_ci	int i;
141c72fcc34Sopenharmony_ci
142c72fcc34Sopenharmony_ci	for (i = 0; i < samples_per_frame; ++i)
143c72fcc34Sopenharmony_ci		free(bufs[i]);
144c72fcc34Sopenharmony_ci
145c72fcc34Sopenharmony_ci	free(bufs);
146c72fcc34Sopenharmony_ci}
147c72fcc34Sopenharmony_ci
148c72fcc34Sopenharmony_cistatic int test_frame_count(struct test_generator *gen,
149c72fcc34Sopenharmony_ci			    snd_pcm_access_t access,
150c72fcc34Sopenharmony_ci			    snd_pcm_format_t sample_format,
151c72fcc34Sopenharmony_ci			    unsigned int samples_per_frame)
152c72fcc34Sopenharmony_ci{
153c72fcc34Sopenharmony_ci	void *(*allocator)(snd_pcm_access_t access,
154c72fcc34Sopenharmony_ci			   snd_pcm_format_t sample_format,
155c72fcc34Sopenharmony_ci			   unsigned int samples_per_frame,
156c72fcc34Sopenharmony_ci			   unsigned int frame_count);
157c72fcc34Sopenharmony_ci	int (*fill)(int fd, void *frame_buffer, snd_pcm_access_t access,
158c72fcc34Sopenharmony_ci		    snd_pcm_format_t sample_format,
159c72fcc34Sopenharmony_ci		    unsigned int samples_per_frame, unsigned int frame_count);
160c72fcc34Sopenharmony_ci	void (*deallocator)(void *frame_buffer, unsigned int samples_per_frame);
161c72fcc34Sopenharmony_ci	void *frame_buffer;
162c72fcc34Sopenharmony_ci	int i;
163c72fcc34Sopenharmony_ci	int err = 0;
164c72fcc34Sopenharmony_ci
165c72fcc34Sopenharmony_ci	if (access != SND_PCM_ACCESS_RW_NONINTERLEAVED) {
166c72fcc34Sopenharmony_ci		allocator = allocate_buf;
167c72fcc34Sopenharmony_ci		fill = fill_buf;
168c72fcc34Sopenharmony_ci		deallocator = deallocate_buf;
169c72fcc34Sopenharmony_ci	} else {
170c72fcc34Sopenharmony_ci		allocator = allocate_vector;
171c72fcc34Sopenharmony_ci		fill = fill_vector;
172c72fcc34Sopenharmony_ci		deallocator = deallocate_vector;
173c72fcc34Sopenharmony_ci	}
174c72fcc34Sopenharmony_ci
175c72fcc34Sopenharmony_ci	frame_buffer = allocator(access, sample_format, samples_per_frame,
176c72fcc34Sopenharmony_ci				 gen->max_frame_count);
177c72fcc34Sopenharmony_ci	if (frame_buffer == NULL)
178c72fcc34Sopenharmony_ci		return -ENOMEM;
179c72fcc34Sopenharmony_ci
180c72fcc34Sopenharmony_ci	err = fill(gen->fd, frame_buffer, access, sample_format,
181c72fcc34Sopenharmony_ci		   samples_per_frame, gen->max_frame_count);
182c72fcc34Sopenharmony_ci	if (err < 0)
183c72fcc34Sopenharmony_ci		goto end;
184c72fcc34Sopenharmony_ci
185c72fcc34Sopenharmony_ci
186c72fcc34Sopenharmony_ci	for (i = gen->min_frame_count;
187c72fcc34Sopenharmony_ci	     i <= gen->max_frame_count; i += gen->step_frame_count) {
188c72fcc34Sopenharmony_ci		err = gen->cb(gen, access ,sample_format, samples_per_frame,
189c72fcc34Sopenharmony_ci			      frame_buffer, i);
190c72fcc34Sopenharmony_ci		if (err < 0)
191c72fcc34Sopenharmony_ci			break;
192c72fcc34Sopenharmony_ci	}
193c72fcc34Sopenharmony_ciend:
194c72fcc34Sopenharmony_ci	deallocator(frame_buffer, samples_per_frame);
195c72fcc34Sopenharmony_ci
196c72fcc34Sopenharmony_ci	return err;
197c72fcc34Sopenharmony_ci}
198c72fcc34Sopenharmony_ci
199c72fcc34Sopenharmony_cistatic int test_samples_per_frame(struct test_generator *gen,
200c72fcc34Sopenharmony_ci				  snd_pcm_access_t access,
201c72fcc34Sopenharmony_ci				  snd_pcm_format_t sample_format)
202c72fcc34Sopenharmony_ci{
203c72fcc34Sopenharmony_ci	int i;
204c72fcc34Sopenharmony_ci	int err = 0;
205c72fcc34Sopenharmony_ci
206c72fcc34Sopenharmony_ci	for (i = gen->min_samples_per_frame;
207c72fcc34Sopenharmony_ci	     i <= gen->max_samples_per_frame; ++i) {
208c72fcc34Sopenharmony_ci		err = test_frame_count(gen, access, sample_format, i);
209c72fcc34Sopenharmony_ci		if (err < 0)
210c72fcc34Sopenharmony_ci			break;
211c72fcc34Sopenharmony_ci	}
212c72fcc34Sopenharmony_ci
213c72fcc34Sopenharmony_ci	return err;
214c72fcc34Sopenharmony_ci}
215c72fcc34Sopenharmony_ci
216c72fcc34Sopenharmony_cistatic int test_sample_format(struct test_generator *gen,
217c72fcc34Sopenharmony_ci			      snd_pcm_access_t access)
218c72fcc34Sopenharmony_ci{
219c72fcc34Sopenharmony_ci	int i;
220c72fcc34Sopenharmony_ci	int err = 0;
221c72fcc34Sopenharmony_ci
222c72fcc34Sopenharmony_ci	for (i = 0; i <= SND_PCM_FORMAT_LAST; ++i) {
223c72fcc34Sopenharmony_ci		if (!((1ull << i) & gen->sample_format_mask))
224c72fcc34Sopenharmony_ci			continue;
225c72fcc34Sopenharmony_ci
226c72fcc34Sopenharmony_ci		err = test_samples_per_frame(gen, access, i);
227c72fcc34Sopenharmony_ci		if (err < 0)
228c72fcc34Sopenharmony_ci			break;
229c72fcc34Sopenharmony_ci	}
230c72fcc34Sopenharmony_ci
231c72fcc34Sopenharmony_ci	return err;
232c72fcc34Sopenharmony_ci}
233c72fcc34Sopenharmony_ci
234c72fcc34Sopenharmony_cistatic int test_access(struct test_generator *gen)
235c72fcc34Sopenharmony_ci{
236c72fcc34Sopenharmony_ci	int i;
237c72fcc34Sopenharmony_ci	int err = 0;
238c72fcc34Sopenharmony_ci
239c72fcc34Sopenharmony_ci	for (i = 0; i <= SND_PCM_ACCESS_LAST; ++i) {
240c72fcc34Sopenharmony_ci		if (!((1ull << i) & gen->access_mask))
241c72fcc34Sopenharmony_ci			continue;
242c72fcc34Sopenharmony_ci
243c72fcc34Sopenharmony_ci		err = test_sample_format(gen, i);
244c72fcc34Sopenharmony_ci		if (err < 0)
245c72fcc34Sopenharmony_ci			break;
246c72fcc34Sopenharmony_ci	}
247c72fcc34Sopenharmony_ci	return err;
248c72fcc34Sopenharmony_ci}
249c72fcc34Sopenharmony_ci
250c72fcc34Sopenharmony_ciint generator_context_run(struct test_generator *gen, generator_cb_t cb)
251c72fcc34Sopenharmony_ci{
252c72fcc34Sopenharmony_ci	gen->cb = cb;
253c72fcc34Sopenharmony_ci	return test_access(gen);
254c72fcc34Sopenharmony_ci}
255c72fcc34Sopenharmony_ci
256c72fcc34Sopenharmony_civoid generator_context_destroy(struct test_generator *gen)
257c72fcc34Sopenharmony_ci{
258c72fcc34Sopenharmony_ci	free(gen->private_data);
259c72fcc34Sopenharmony_ci	close(gen->fd);
260c72fcc34Sopenharmony_ci}
261