1d5ac70f0Sopenharmony_ci/**
2d5ac70f0Sopenharmony_ci * \file pcm/pcm_ioplug.c
3d5ac70f0Sopenharmony_ci * \ingroup Plugin_SDK
4d5ac70f0Sopenharmony_ci * \brief I/O Plugin SDK
5d5ac70f0Sopenharmony_ci * \author Takashi Iwai <tiwai@suse.de>
6d5ac70f0Sopenharmony_ci * \date 2005
7d5ac70f0Sopenharmony_ci */
8d5ac70f0Sopenharmony_ci/*
9d5ac70f0Sopenharmony_ci *  PCM - External I/O Plugin SDK
10d5ac70f0Sopenharmony_ci *  Copyright (c) 2005 by Takashi Iwai <tiwai@suse.de>
11d5ac70f0Sopenharmony_ci *
12d5ac70f0Sopenharmony_ci *
13d5ac70f0Sopenharmony_ci *   This library is free software; you can redistribute it and/or modify
14d5ac70f0Sopenharmony_ci *   it under the terms of the GNU Lesser General Public License as
15d5ac70f0Sopenharmony_ci *   published by the Free Software Foundation; either version 2.1 of
16d5ac70f0Sopenharmony_ci *   the License, or (at your option) any later version.
17d5ac70f0Sopenharmony_ci *
18d5ac70f0Sopenharmony_ci *   This program is distributed in the hope that it will be useful,
19d5ac70f0Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
20d5ac70f0Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21d5ac70f0Sopenharmony_ci *   GNU Lesser General Public License for more details.
22d5ac70f0Sopenharmony_ci *
23d5ac70f0Sopenharmony_ci *   You should have received a copy of the GNU Lesser General Public
24d5ac70f0Sopenharmony_ci *   License along with this library; if not, write to the Free Software
25d5ac70f0Sopenharmony_ci *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
26d5ac70f0Sopenharmony_ci *
27d5ac70f0Sopenharmony_ci */
28d5ac70f0Sopenharmony_ci
29d5ac70f0Sopenharmony_ci#include "pcm_local.h"
30d5ac70f0Sopenharmony_ci#include "pcm_ioplug.h"
31d5ac70f0Sopenharmony_ci#include "pcm_ext_parm.h"
32d5ac70f0Sopenharmony_ci#include "pcm_generic.h"
33d5ac70f0Sopenharmony_ci
34d5ac70f0Sopenharmony_ci#ifndef PIC
35d5ac70f0Sopenharmony_ci/* entry for static linking */
36d5ac70f0Sopenharmony_ciconst char *_snd_module_pcm_ioplug = "";
37d5ac70f0Sopenharmony_ci#endif
38d5ac70f0Sopenharmony_ci
39d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
40d5ac70f0Sopenharmony_ci
41d5ac70f0Sopenharmony_ci/* hw_params */
42d5ac70f0Sopenharmony_citypedef struct snd_pcm_ioplug_priv {
43d5ac70f0Sopenharmony_ci	snd_pcm_ioplug_t *data;
44d5ac70f0Sopenharmony_ci	struct snd_ext_parm params[SND_PCM_IOPLUG_HW_PARAMS];
45d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t last_hw;
46d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t avail_max;
47d5ac70f0Sopenharmony_ci	snd_htimestamp_t trigger_tstamp;
48d5ac70f0Sopenharmony_ci} ioplug_priv_t;
49d5ac70f0Sopenharmony_ci
50d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_drop(snd_pcm_t *pcm);
51d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm);
52d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space);
53d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
54d5ac70f0Sopenharmony_ci
55d5ac70f0Sopenharmony_ci/* update the hw pointer */
56d5ac70f0Sopenharmony_ci/* called in lock */
57d5ac70f0Sopenharmony_cistatic void snd_pcm_ioplug_hw_ptr_update(snd_pcm_t *pcm)
58d5ac70f0Sopenharmony_ci{
59d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
60d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t hw;
61d5ac70f0Sopenharmony_ci
62d5ac70f0Sopenharmony_ci	hw = io->data->callback->pointer(io->data);
63d5ac70f0Sopenharmony_ci	if (hw >= 0) {
64d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t delta;
65d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t avail;
66d5ac70f0Sopenharmony_ci
67d5ac70f0Sopenharmony_ci		if ((snd_pcm_uframes_t)hw >= io->last_hw)
68d5ac70f0Sopenharmony_ci			delta = hw - io->last_hw;
69d5ac70f0Sopenharmony_ci		else {
70d5ac70f0Sopenharmony_ci			const snd_pcm_uframes_t wrap_point =
71d5ac70f0Sopenharmony_ci				(io->data->flags & SND_PCM_IOPLUG_FLAG_BOUNDARY_WA) ?
72d5ac70f0Sopenharmony_ci					pcm->boundary : pcm->buffer_size;
73d5ac70f0Sopenharmony_ci			delta = wrap_point + hw - io->last_hw;
74d5ac70f0Sopenharmony_ci		}
75d5ac70f0Sopenharmony_ci		snd_pcm_mmap_hw_forward(io->data->pcm, delta);
76d5ac70f0Sopenharmony_ci		/* stop the stream if all samples are drained */
77d5ac70f0Sopenharmony_ci		if (io->data->state == SND_PCM_STATE_DRAINING) {
78d5ac70f0Sopenharmony_ci			avail = snd_pcm_mmap_avail(pcm);
79d5ac70f0Sopenharmony_ci			if (avail >= pcm->buffer_size)
80d5ac70f0Sopenharmony_ci				snd_pcm_ioplug_drop(pcm);
81d5ac70f0Sopenharmony_ci		}
82d5ac70f0Sopenharmony_ci		io->last_hw = (snd_pcm_uframes_t)hw;
83d5ac70f0Sopenharmony_ci	} else {
84d5ac70f0Sopenharmony_ci		if (io->data->state == SND_PCM_STATE_DRAINING)
85d5ac70f0Sopenharmony_ci			snd_pcm_ioplug_drop(pcm);
86d5ac70f0Sopenharmony_ci		else
87d5ac70f0Sopenharmony_ci			io->data->state = SNDRV_PCM_STATE_XRUN;
88d5ac70f0Sopenharmony_ci	}
89d5ac70f0Sopenharmony_ci}
90d5ac70f0Sopenharmony_ci
91d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
92d5ac70f0Sopenharmony_ci{
93d5ac70f0Sopenharmony_ci	memset(info, 0, sizeof(*info));
94d5ac70f0Sopenharmony_ci	info->stream = pcm->stream;
95d5ac70f0Sopenharmony_ci	info->card = -1;
96d5ac70f0Sopenharmony_ci	if (pcm->name) {
97d5ac70f0Sopenharmony_ci		snd_strlcpy((char *)info->id, pcm->name, sizeof(info->id));
98d5ac70f0Sopenharmony_ci		snd_strlcpy((char *)info->name, pcm->name, sizeof(info->name));
99d5ac70f0Sopenharmony_ci		snd_strlcpy((char *)info->subname, pcm->name, sizeof(info->subname));
100d5ac70f0Sopenharmony_ci	}
101d5ac70f0Sopenharmony_ci	info->subdevices_count = 1;
102d5ac70f0Sopenharmony_ci	return 0;
103d5ac70f0Sopenharmony_ci}
104d5ac70f0Sopenharmony_ci
105d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
106d5ac70f0Sopenharmony_ci{
107d5ac70f0Sopenharmony_ci	return snd_pcm_channel_info_shm(pcm, info, -1);
108d5ac70f0Sopenharmony_ci}
109d5ac70f0Sopenharmony_ci
110d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
111d5ac70f0Sopenharmony_ci{
112d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
113d5ac70f0Sopenharmony_ci
114d5ac70f0Sopenharmony_ci	if (io->data->version >= 0x010001 &&
115d5ac70f0Sopenharmony_ci	    io->data->callback->delay)
116d5ac70f0Sopenharmony_ci		return io->data->callback->delay(io->data, delayp);
117d5ac70f0Sopenharmony_ci	else {
118d5ac70f0Sopenharmony_ci		snd_pcm_ioplug_hw_ptr_update(pcm);
119d5ac70f0Sopenharmony_ci		*delayp = snd_pcm_mmap_delay(pcm);
120d5ac70f0Sopenharmony_ci	}
121d5ac70f0Sopenharmony_ci	return 0;
122d5ac70f0Sopenharmony_ci}
123d5ac70f0Sopenharmony_ci
124d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
125d5ac70f0Sopenharmony_ci{
126d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
127d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t sd;
128d5ac70f0Sopenharmony_ci
129d5ac70f0Sopenharmony_ci	memset(status, 0, sizeof(*status));
130d5ac70f0Sopenharmony_ci	snd_pcm_ioplug_hw_ptr_update(pcm);
131d5ac70f0Sopenharmony_ci	status->state = io->data->state;
132d5ac70f0Sopenharmony_ci	status->trigger_tstamp = io->trigger_tstamp;
133d5ac70f0Sopenharmony_ci	gettimestamp(&status->tstamp, pcm->tstamp_type);
134d5ac70f0Sopenharmony_ci	status->avail = snd_pcm_mmap_avail(pcm);
135d5ac70f0Sopenharmony_ci	status->avail_max = io->avail_max;
136d5ac70f0Sopenharmony_ci	status->appl_ptr = *pcm->appl.ptr;
137d5ac70f0Sopenharmony_ci	status->hw_ptr = *pcm->hw.ptr;
138d5ac70f0Sopenharmony_ci	if (snd_pcm_ioplug_delay(pcm, &sd) < 0)
139d5ac70f0Sopenharmony_ci		sd = snd_pcm_mmap_delay(pcm);
140d5ac70f0Sopenharmony_ci	status->delay = sd;
141d5ac70f0Sopenharmony_ci	return 0;
142d5ac70f0Sopenharmony_ci}
143d5ac70f0Sopenharmony_ci
144d5ac70f0Sopenharmony_cistatic snd_pcm_state_t snd_pcm_ioplug_state(snd_pcm_t *pcm)
145d5ac70f0Sopenharmony_ci{
146d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
147d5ac70f0Sopenharmony_ci	return io->data->state;
148d5ac70f0Sopenharmony_ci}
149d5ac70f0Sopenharmony_ci
150d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_hwsync(snd_pcm_t *pcm)
151d5ac70f0Sopenharmony_ci{
152d5ac70f0Sopenharmony_ci	snd_pcm_ioplug_hw_ptr_update(pcm);
153d5ac70f0Sopenharmony_ci	return 0;
154d5ac70f0Sopenharmony_ci}
155d5ac70f0Sopenharmony_ci
156d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_reset(snd_pcm_t *pcm)
157d5ac70f0Sopenharmony_ci{
158d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
159d5ac70f0Sopenharmony_ci
160d5ac70f0Sopenharmony_ci	io->data->appl_ptr = 0;
161d5ac70f0Sopenharmony_ci	io->data->hw_ptr = 0;
162d5ac70f0Sopenharmony_ci	io->last_hw = 0;
163d5ac70f0Sopenharmony_ci	io->avail_max = 0;
164d5ac70f0Sopenharmony_ci	return 0;
165d5ac70f0Sopenharmony_ci}
166d5ac70f0Sopenharmony_ci
167d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_prepare(snd_pcm_t *pcm)
168d5ac70f0Sopenharmony_ci{
169d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
170d5ac70f0Sopenharmony_ci	int err = 0;
171d5ac70f0Sopenharmony_ci
172d5ac70f0Sopenharmony_ci	snd_pcm_ioplug_reset(pcm);
173d5ac70f0Sopenharmony_ci	if (io->data->callback->prepare) {
174d5ac70f0Sopenharmony_ci		snd_pcm_unlock(pcm); /* to avoid deadlock */
175d5ac70f0Sopenharmony_ci		err = io->data->callback->prepare(io->data);
176d5ac70f0Sopenharmony_ci		snd_pcm_lock(pcm);
177d5ac70f0Sopenharmony_ci	}
178d5ac70f0Sopenharmony_ci	if (err < 0)
179d5ac70f0Sopenharmony_ci		return err;
180d5ac70f0Sopenharmony_ci
181d5ac70f0Sopenharmony_ci	io->data->state = SND_PCM_STATE_PREPARED;
182d5ac70f0Sopenharmony_ci	return err;
183d5ac70f0Sopenharmony_ci}
184d5ac70f0Sopenharmony_ci
185d5ac70f0Sopenharmony_cistatic const int hw_params_type[SND_PCM_IOPLUG_HW_PARAMS] = {
186d5ac70f0Sopenharmony_ci	[SND_PCM_IOPLUG_HW_ACCESS] = SND_PCM_HW_PARAM_ACCESS,
187d5ac70f0Sopenharmony_ci	[SND_PCM_IOPLUG_HW_FORMAT] = SND_PCM_HW_PARAM_FORMAT,
188d5ac70f0Sopenharmony_ci	[SND_PCM_IOPLUG_HW_CHANNELS] = SND_PCM_HW_PARAM_CHANNELS,
189d5ac70f0Sopenharmony_ci	[SND_PCM_IOPLUG_HW_RATE] = SND_PCM_HW_PARAM_RATE,
190d5ac70f0Sopenharmony_ci	[SND_PCM_IOPLUG_HW_PERIOD_BYTES] = SND_PCM_HW_PARAM_PERIOD_BYTES,
191d5ac70f0Sopenharmony_ci	[SND_PCM_IOPLUG_HW_BUFFER_BYTES] = SND_PCM_HW_PARAM_BUFFER_BYTES,
192d5ac70f0Sopenharmony_ci	[SND_PCM_IOPLUG_HW_PERIODS] = SND_PCM_HW_PARAM_PERIODS,
193d5ac70f0Sopenharmony_ci};
194d5ac70f0Sopenharmony_ci
195d5ac70f0Sopenharmony_ci/* x = a * b */
196d5ac70f0Sopenharmony_cistatic int rule_mul(snd_pcm_hw_params_t *params, int x, int a, int b)
197d5ac70f0Sopenharmony_ci{
198d5ac70f0Sopenharmony_ci	snd_interval_t t;
199d5ac70f0Sopenharmony_ci
200d5ac70f0Sopenharmony_ci	snd_interval_mul(hw_param_interval(params, a),
201d5ac70f0Sopenharmony_ci			 hw_param_interval(params, b), &t);
202d5ac70f0Sopenharmony_ci	return snd_interval_refine(hw_param_interval(params, x), &t);
203d5ac70f0Sopenharmony_ci}
204d5ac70f0Sopenharmony_ci
205d5ac70f0Sopenharmony_ci/* x = a / b */
206d5ac70f0Sopenharmony_cistatic int rule_div(snd_pcm_hw_params_t *params, int x, int a, int b)
207d5ac70f0Sopenharmony_ci{
208d5ac70f0Sopenharmony_ci	snd_interval_t t;
209d5ac70f0Sopenharmony_ci
210d5ac70f0Sopenharmony_ci	snd_interval_div(hw_param_interval(params, a),
211d5ac70f0Sopenharmony_ci			 hw_param_interval(params, b), &t);
212d5ac70f0Sopenharmony_ci	return snd_interval_refine(hw_param_interval(params, x), &t);
213d5ac70f0Sopenharmony_ci}
214d5ac70f0Sopenharmony_ci
215d5ac70f0Sopenharmony_ci/* x = a * b / k */
216d5ac70f0Sopenharmony_cistatic int rule_muldivk(snd_pcm_hw_params_t *params, int x, int a, int b, int k)
217d5ac70f0Sopenharmony_ci{
218d5ac70f0Sopenharmony_ci	snd_interval_t t;
219d5ac70f0Sopenharmony_ci
220d5ac70f0Sopenharmony_ci	snd_interval_muldivk(hw_param_interval(params, a),
221d5ac70f0Sopenharmony_ci			     hw_param_interval(params, b), k, &t);
222d5ac70f0Sopenharmony_ci	return snd_interval_refine(hw_param_interval(params, x), &t);
223d5ac70f0Sopenharmony_ci}
224d5ac70f0Sopenharmony_ci
225d5ac70f0Sopenharmony_ci/* x = a * k / b */
226d5ac70f0Sopenharmony_cistatic int rule_mulkdiv(snd_pcm_hw_params_t *params, int x, int a, int k, int b)
227d5ac70f0Sopenharmony_ci{
228d5ac70f0Sopenharmony_ci	snd_interval_t t;
229d5ac70f0Sopenharmony_ci
230d5ac70f0Sopenharmony_ci	snd_interval_mulkdiv(hw_param_interval(params, a), k,
231d5ac70f0Sopenharmony_ci			     hw_param_interval(params, b), &t);
232d5ac70f0Sopenharmony_ci	return snd_interval_refine(hw_param_interval(params, x), &t);
233d5ac70f0Sopenharmony_ci}
234d5ac70f0Sopenharmony_ci
235d5ac70f0Sopenharmony_ci#if 0
236d5ac70f0Sopenharmony_cistatic void dump_parm(snd_pcm_hw_params_t *params)
237d5ac70f0Sopenharmony_ci{
238d5ac70f0Sopenharmony_ci	snd_output_t *log;
239d5ac70f0Sopenharmony_ci	snd_output_stdio_attach(&log, stderr, 0);
240d5ac70f0Sopenharmony_ci	snd_pcm_hw_params_dump(params, log);
241d5ac70f0Sopenharmony_ci	snd_output_close(log);
242d5ac70f0Sopenharmony_ci}
243d5ac70f0Sopenharmony_ci#endif
244d5ac70f0Sopenharmony_ci
245d5ac70f0Sopenharmony_ci/* refine *_TIME and *_SIZE, then update *_BYTES */
246d5ac70f0Sopenharmony_cistatic int refine_time_and_size(snd_pcm_hw_params_t *params,
247d5ac70f0Sopenharmony_ci				int time, int size, int bytes)
248d5ac70f0Sopenharmony_ci{
249d5ac70f0Sopenharmony_ci	int err, change1 = 0;
250d5ac70f0Sopenharmony_ci
251d5ac70f0Sopenharmony_ci	/* size = time * rate / 1000000 */
252d5ac70f0Sopenharmony_ci	err = rule_muldivk(params, size, time,
253d5ac70f0Sopenharmony_ci			   SND_PCM_HW_PARAM_RATE, 1000000);
254d5ac70f0Sopenharmony_ci	if (err < 0)
255d5ac70f0Sopenharmony_ci		return err;
256d5ac70f0Sopenharmony_ci	change1 |= err;
257d5ac70f0Sopenharmony_ci
258d5ac70f0Sopenharmony_ci	/* bytes = size * framebits / 8 */
259d5ac70f0Sopenharmony_ci	err = rule_muldivk(params, bytes, size,
260d5ac70f0Sopenharmony_ci			   SND_PCM_HW_PARAM_FRAME_BITS, 8);
261d5ac70f0Sopenharmony_ci	if (err < 0)
262d5ac70f0Sopenharmony_ci		return err;
263d5ac70f0Sopenharmony_ci	change1 |= err;
264d5ac70f0Sopenharmony_ci	return change1;
265d5ac70f0Sopenharmony_ci}
266d5ac70f0Sopenharmony_ci
267d5ac70f0Sopenharmony_ci/* refine *_TIME and *_SIZE from *_BYTES */
268d5ac70f0Sopenharmony_cistatic int refine_back_time_and_size(snd_pcm_hw_params_t *params,
269d5ac70f0Sopenharmony_ci				     int time, int size, int bytes)
270d5ac70f0Sopenharmony_ci{
271d5ac70f0Sopenharmony_ci	int err;
272d5ac70f0Sopenharmony_ci
273d5ac70f0Sopenharmony_ci	/* size = bytes * 8 / framebits */
274d5ac70f0Sopenharmony_ci	err = rule_mulkdiv(params, size, bytes, 8, SND_PCM_HW_PARAM_FRAME_BITS);
275d5ac70f0Sopenharmony_ci	if (err < 0)
276d5ac70f0Sopenharmony_ci		return err;
277d5ac70f0Sopenharmony_ci	/* time = size * 1000000 / rate */
278d5ac70f0Sopenharmony_ci	err = rule_mulkdiv(params, time, size, 1000000, SND_PCM_HW_PARAM_RATE);
279d5ac70f0Sopenharmony_ci	if (err < 0)
280d5ac70f0Sopenharmony_ci		return err;
281d5ac70f0Sopenharmony_ci	return 0;
282d5ac70f0Sopenharmony_ci}
283d5ac70f0Sopenharmony_ci
284d5ac70f0Sopenharmony_ci
285d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
286d5ac70f0Sopenharmony_ci{
287d5ac70f0Sopenharmony_ci	int change = 0, change1, change2, err;
288d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
289d5ac70f0Sopenharmony_ci	struct snd_ext_parm *p;
290d5ac70f0Sopenharmony_ci	unsigned int i;
291d5ac70f0Sopenharmony_ci
292d5ac70f0Sopenharmony_ci	/* access, format */
293d5ac70f0Sopenharmony_ci	for (i = SND_PCM_IOPLUG_HW_ACCESS; i <= SND_PCM_IOPLUG_HW_FORMAT; i++) {
294d5ac70f0Sopenharmony_ci		err = snd_ext_parm_mask_refine(hw_param_mask(params, hw_params_type[i]),
295d5ac70f0Sopenharmony_ci					       io->params, i);
296d5ac70f0Sopenharmony_ci		if (err < 0)
297d5ac70f0Sopenharmony_ci			return err;
298d5ac70f0Sopenharmony_ci		change |= err;
299d5ac70f0Sopenharmony_ci	}
300d5ac70f0Sopenharmony_ci	/* channels, rate */
301d5ac70f0Sopenharmony_ci	for (; i <= SND_PCM_IOPLUG_HW_RATE; i++) {
302d5ac70f0Sopenharmony_ci		err = snd_ext_parm_interval_refine(hw_param_interval(params, hw_params_type[i]),
303d5ac70f0Sopenharmony_ci						   io->params, i);
304d5ac70f0Sopenharmony_ci		if (err < 0)
305d5ac70f0Sopenharmony_ci			return err;
306d5ac70f0Sopenharmony_ci		change |= err;
307d5ac70f0Sopenharmony_ci	}
308d5ac70f0Sopenharmony_ci
309d5ac70f0Sopenharmony_ci	if (params->rmask & ((1 << SND_PCM_HW_PARAM_ACCESS) |
310d5ac70f0Sopenharmony_ci			     (1 << SND_PCM_HW_PARAM_FORMAT) |
311d5ac70f0Sopenharmony_ci			     (1 << SND_PCM_HW_PARAM_SUBFORMAT) |
312d5ac70f0Sopenharmony_ci			     (1 << SND_PCM_HW_PARAM_CHANNELS) |
313d5ac70f0Sopenharmony_ci			     (1 << SND_PCM_HW_PARAM_RATE))) {
314d5ac70f0Sopenharmony_ci		err = snd_pcm_hw_refine_soft(pcm, params);
315d5ac70f0Sopenharmony_ci		if (err < 0)
316d5ac70f0Sopenharmony_ci			return err;
317d5ac70f0Sopenharmony_ci		change |= err;
318d5ac70f0Sopenharmony_ci	}
319d5ac70f0Sopenharmony_ci
320d5ac70f0Sopenharmony_ci	change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
321d5ac70f0Sopenharmony_ci				       SND_PCM_HW_PARAM_PERIOD_SIZE,
322d5ac70f0Sopenharmony_ci				       SND_PCM_HW_PARAM_PERIOD_BYTES);
323d5ac70f0Sopenharmony_ci	if (change1 < 0)
324d5ac70f0Sopenharmony_ci		return change1;
325d5ac70f0Sopenharmony_ci	err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES),
326d5ac70f0Sopenharmony_ci					   io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES);
327d5ac70f0Sopenharmony_ci	if (err < 0)
328d5ac70f0Sopenharmony_ci		return err;
329d5ac70f0Sopenharmony_ci	change1 |= err;
330d5ac70f0Sopenharmony_ci	if (change1) {
331d5ac70f0Sopenharmony_ci		change |= change1;
332d5ac70f0Sopenharmony_ci		err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
333d5ac70f0Sopenharmony_ci						SND_PCM_HW_PARAM_PERIOD_SIZE,
334d5ac70f0Sopenharmony_ci						SND_PCM_HW_PARAM_PERIOD_BYTES);
335d5ac70f0Sopenharmony_ci		if (err < 0)
336d5ac70f0Sopenharmony_ci			return err;
337d5ac70f0Sopenharmony_ci	}
338d5ac70f0Sopenharmony_ci
339d5ac70f0Sopenharmony_ci	change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME,
340d5ac70f0Sopenharmony_ci				       SND_PCM_HW_PARAM_BUFFER_SIZE,
341d5ac70f0Sopenharmony_ci				       SND_PCM_HW_PARAM_BUFFER_BYTES);
342d5ac70f0Sopenharmony_ci	if (change1 < 0)
343d5ac70f0Sopenharmony_ci		return change1;
344d5ac70f0Sopenharmony_ci	change |= change1;
345d5ac70f0Sopenharmony_ci
346d5ac70f0Sopenharmony_ci	do {
347d5ac70f0Sopenharmony_ci		change2 = 0;
348d5ac70f0Sopenharmony_ci		err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_BUFFER_BYTES),
349d5ac70f0Sopenharmony_ci						   io->params, SND_PCM_IOPLUG_HW_BUFFER_BYTES);
350d5ac70f0Sopenharmony_ci		if (err < 0)
351d5ac70f0Sopenharmony_ci			return err;
352d5ac70f0Sopenharmony_ci		change2 |= err;
353d5ac70f0Sopenharmony_ci		/* periods = buffer_bytes / period_bytes */
354d5ac70f0Sopenharmony_ci		err = rule_div(params, SND_PCM_HW_PARAM_PERIODS,
355d5ac70f0Sopenharmony_ci			       SND_PCM_HW_PARAM_BUFFER_BYTES,
356d5ac70f0Sopenharmony_ci			       SND_PCM_HW_PARAM_PERIOD_BYTES);
357d5ac70f0Sopenharmony_ci		if (err < 0)
358d5ac70f0Sopenharmony_ci			return err;
359d5ac70f0Sopenharmony_ci		change2 |= err;
360d5ac70f0Sopenharmony_ci		err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIODS),
361d5ac70f0Sopenharmony_ci						   io->params, SND_PCM_IOPLUG_HW_PERIODS);
362d5ac70f0Sopenharmony_ci		if (err < 0)
363d5ac70f0Sopenharmony_ci			return err;
364d5ac70f0Sopenharmony_ci		change2 |= err;
365d5ac70f0Sopenharmony_ci		/* buffer_bytes = periods * period_bytes */
366d5ac70f0Sopenharmony_ci		err = rule_mul(params, SND_PCM_HW_PARAM_BUFFER_BYTES,
367d5ac70f0Sopenharmony_ci			       SND_PCM_HW_PARAM_PERIOD_BYTES,
368d5ac70f0Sopenharmony_ci			       SND_PCM_HW_PARAM_PERIODS);
369d5ac70f0Sopenharmony_ci		if (err < 0)
370d5ac70f0Sopenharmony_ci			return err;
371d5ac70f0Sopenharmony_ci		change2 |= err;
372d5ac70f0Sopenharmony_ci		change1 |= change2;
373d5ac70f0Sopenharmony_ci	} while (change2);
374d5ac70f0Sopenharmony_ci	change |= change1;
375d5ac70f0Sopenharmony_ci
376d5ac70f0Sopenharmony_ci	if (change1) {
377d5ac70f0Sopenharmony_ci		err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME,
378d5ac70f0Sopenharmony_ci						SND_PCM_HW_PARAM_BUFFER_SIZE,
379d5ac70f0Sopenharmony_ci						SND_PCM_HW_PARAM_BUFFER_BYTES);
380d5ac70f0Sopenharmony_ci		if (err < 0)
381d5ac70f0Sopenharmony_ci			return err;
382d5ac70f0Sopenharmony_ci	}
383d5ac70f0Sopenharmony_ci
384d5ac70f0Sopenharmony_ci	/* period_bytes = buffer_bytes / periods */
385d5ac70f0Sopenharmony_ci	err = rule_div(params, SND_PCM_HW_PARAM_PERIOD_BYTES,
386d5ac70f0Sopenharmony_ci		       SND_PCM_HW_PARAM_BUFFER_BYTES,
387d5ac70f0Sopenharmony_ci		       SND_PCM_HW_PARAM_PERIODS);
388d5ac70f0Sopenharmony_ci	if (err < 0)
389d5ac70f0Sopenharmony_ci		return err;
390d5ac70f0Sopenharmony_ci	if (err) {
391d5ac70f0Sopenharmony_ci		/* update period_size and period_time */
392d5ac70f0Sopenharmony_ci		change |= err;
393d5ac70f0Sopenharmony_ci		err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES),
394d5ac70f0Sopenharmony_ci						   io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES);
395d5ac70f0Sopenharmony_ci		if (err < 0)
396d5ac70f0Sopenharmony_ci			return err;
397d5ac70f0Sopenharmony_ci		err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
398d5ac70f0Sopenharmony_ci						SND_PCM_HW_PARAM_PERIOD_SIZE,
399d5ac70f0Sopenharmony_ci						SND_PCM_HW_PARAM_PERIOD_BYTES);
400d5ac70f0Sopenharmony_ci		if (err < 0)
401d5ac70f0Sopenharmony_ci			return err;
402d5ac70f0Sopenharmony_ci	}
403d5ac70f0Sopenharmony_ci
404d5ac70f0Sopenharmony_ci	params->info = SND_PCM_INFO_BLOCK_TRANSFER;
405d5ac70f0Sopenharmony_ci	p = &io->params[SND_PCM_IOPLUG_HW_ACCESS];
406d5ac70f0Sopenharmony_ci	if (p->active) {
407d5ac70f0Sopenharmony_ci		for (i = 0; i < p->num_list; i++)
408d5ac70f0Sopenharmony_ci			switch (p->list[i]) {
409d5ac70f0Sopenharmony_ci			case SND_PCM_ACCESS_MMAP_INTERLEAVED:
410d5ac70f0Sopenharmony_ci			case SND_PCM_ACCESS_RW_INTERLEAVED:
411d5ac70f0Sopenharmony_ci				params->info |= SND_PCM_INFO_INTERLEAVED;
412d5ac70f0Sopenharmony_ci				break;
413d5ac70f0Sopenharmony_ci			case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
414d5ac70f0Sopenharmony_ci			case SND_PCM_ACCESS_RW_NONINTERLEAVED:
415d5ac70f0Sopenharmony_ci				params->info |= SND_PCM_INFO_NONINTERLEAVED;
416d5ac70f0Sopenharmony_ci				break;
417d5ac70f0Sopenharmony_ci			}
418d5ac70f0Sopenharmony_ci	}
419d5ac70f0Sopenharmony_ci	if (io->data->callback->pause)
420d5ac70f0Sopenharmony_ci		params->info |= SND_PCM_INFO_PAUSE;
421d5ac70f0Sopenharmony_ci	if (io->data->callback->resume)
422d5ac70f0Sopenharmony_ci		params->info |= SND_PCM_INFO_RESUME;
423d5ac70f0Sopenharmony_ci
424d5ac70f0Sopenharmony_ci#if 0
425d5ac70f0Sopenharmony_ci	fprintf(stderr, "XXX\n");
426d5ac70f0Sopenharmony_ci	dump_parm(params);
427d5ac70f0Sopenharmony_ci#endif
428d5ac70f0Sopenharmony_ci	return change;
429d5ac70f0Sopenharmony_ci}
430d5ac70f0Sopenharmony_ci
431d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
432d5ac70f0Sopenharmony_ci{
433d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
434d5ac70f0Sopenharmony_ci	int err;
435d5ac70f0Sopenharmony_ci
436d5ac70f0Sopenharmony_ci	INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access);
437d5ac70f0Sopenharmony_ci	INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format);
438d5ac70f0Sopenharmony_ci	INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels);
439d5ac70f0Sopenharmony_ci	INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0);
440d5ac70f0Sopenharmony_ci	INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0);
441d5ac70f0Sopenharmony_ci	INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size);
442d5ac70f0Sopenharmony_ci	if (io->data->callback->hw_params) {
443d5ac70f0Sopenharmony_ci		err = io->data->callback->hw_params(io->data, params);
444d5ac70f0Sopenharmony_ci		if (err < 0)
445d5ac70f0Sopenharmony_ci			return err;
446d5ac70f0Sopenharmony_ci		INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access);
447d5ac70f0Sopenharmony_ci		INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format);
448d5ac70f0Sopenharmony_ci		INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels);
449d5ac70f0Sopenharmony_ci		INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0);
450d5ac70f0Sopenharmony_ci		INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0);
451d5ac70f0Sopenharmony_ci		INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size);
452d5ac70f0Sopenharmony_ci	}
453d5ac70f0Sopenharmony_ci	return 0;
454d5ac70f0Sopenharmony_ci}
455d5ac70f0Sopenharmony_ci
456d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_hw_free(snd_pcm_t *pcm)
457d5ac70f0Sopenharmony_ci{
458d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
459d5ac70f0Sopenharmony_ci
460d5ac70f0Sopenharmony_ci	if (io->data->callback->hw_free)
461d5ac70f0Sopenharmony_ci		return io->data->callback->hw_free(io->data);
462d5ac70f0Sopenharmony_ci	return 0;
463d5ac70f0Sopenharmony_ci}
464d5ac70f0Sopenharmony_ci
465d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
466d5ac70f0Sopenharmony_ci{
467d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
468d5ac70f0Sopenharmony_ci	int err;
469d5ac70f0Sopenharmony_ci
470d5ac70f0Sopenharmony_ci	if (!io->data->callback->sw_params)
471d5ac70f0Sopenharmony_ci		return 0;
472d5ac70f0Sopenharmony_ci
473d5ac70f0Sopenharmony_ci	snd_pcm_unlock(pcm); /* to avoid deadlock */
474d5ac70f0Sopenharmony_ci	err = io->data->callback->sw_params(io->data, params);
475d5ac70f0Sopenharmony_ci	snd_pcm_lock(pcm);
476d5ac70f0Sopenharmony_ci
477d5ac70f0Sopenharmony_ci	return err;
478d5ac70f0Sopenharmony_ci}
479d5ac70f0Sopenharmony_ci
480d5ac70f0Sopenharmony_ci
481d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_start(snd_pcm_t *pcm)
482d5ac70f0Sopenharmony_ci{
483d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
484d5ac70f0Sopenharmony_ci	int err;
485d5ac70f0Sopenharmony_ci
486d5ac70f0Sopenharmony_ci	if (io->data->state != SND_PCM_STATE_PREPARED)
487d5ac70f0Sopenharmony_ci		return -EBADFD;
488d5ac70f0Sopenharmony_ci
489d5ac70f0Sopenharmony_ci	err = io->data->callback->start(io->data);
490d5ac70f0Sopenharmony_ci	if (err < 0)
491d5ac70f0Sopenharmony_ci		return err;
492d5ac70f0Sopenharmony_ci
493d5ac70f0Sopenharmony_ci	gettimestamp(&io->trigger_tstamp, pcm->tstamp_type);
494d5ac70f0Sopenharmony_ci	io->data->state = SND_PCM_STATE_RUNNING;
495d5ac70f0Sopenharmony_ci
496d5ac70f0Sopenharmony_ci	return 0;
497d5ac70f0Sopenharmony_ci}
498d5ac70f0Sopenharmony_ci
499d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_drop(snd_pcm_t *pcm)
500d5ac70f0Sopenharmony_ci{
501d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
502d5ac70f0Sopenharmony_ci
503d5ac70f0Sopenharmony_ci	if (io->data->state == SND_PCM_STATE_OPEN)
504d5ac70f0Sopenharmony_ci		return -EBADFD;
505d5ac70f0Sopenharmony_ci
506d5ac70f0Sopenharmony_ci	io->data->callback->stop(io->data);
507d5ac70f0Sopenharmony_ci
508d5ac70f0Sopenharmony_ci	gettimestamp(&io->trigger_tstamp, pcm->tstamp_type);
509d5ac70f0Sopenharmony_ci	io->data->state = SND_PCM_STATE_SETUP;
510d5ac70f0Sopenharmony_ci
511d5ac70f0Sopenharmony_ci	return 0;
512d5ac70f0Sopenharmony_ci}
513d5ac70f0Sopenharmony_ci
514d5ac70f0Sopenharmony_cistatic int ioplug_drain_via_poll(snd_pcm_t *pcm)
515d5ac70f0Sopenharmony_ci{
516d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
517d5ac70f0Sopenharmony_ci
518d5ac70f0Sopenharmony_ci	while (io->data->state == SND_PCM_STATE_DRAINING) {
519d5ac70f0Sopenharmony_ci		snd_pcm_ioplug_hw_ptr_update(pcm);
520d5ac70f0Sopenharmony_ci		if (io->data->state != SND_PCM_STATE_DRAINING)
521d5ac70f0Sopenharmony_ci			break;
522d5ac70f0Sopenharmony_ci		/* in non-blocking mode, let application to poll() by itself */
523d5ac70f0Sopenharmony_ci		if (io->data->nonblock)
524d5ac70f0Sopenharmony_ci			return -EAGAIN;
525d5ac70f0Sopenharmony_ci		if (snd_pcm_wait_nocheck(pcm, SND_PCM_WAIT_DRAIN) < 0)
526d5ac70f0Sopenharmony_ci			break;
527d5ac70f0Sopenharmony_ci	}
528d5ac70f0Sopenharmony_ci
529d5ac70f0Sopenharmony_ci	return 0; /* force to drop at error */
530d5ac70f0Sopenharmony_ci}
531d5ac70f0Sopenharmony_ci
532d5ac70f0Sopenharmony_ci/* need own locking */
533d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_drain(snd_pcm_t *pcm)
534d5ac70f0Sopenharmony_ci{
535d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
536d5ac70f0Sopenharmony_ci	int err = 0;
537d5ac70f0Sopenharmony_ci
538d5ac70f0Sopenharmony_ci	snd_pcm_lock(pcm);
539d5ac70f0Sopenharmony_ci	switch (io->data->state) {
540d5ac70f0Sopenharmony_ci	case SND_PCM_STATE_OPEN:
541d5ac70f0Sopenharmony_ci	case SND_PCM_STATE_DISCONNECTED:
542d5ac70f0Sopenharmony_ci	case SND_PCM_STATE_SUSPENDED:
543d5ac70f0Sopenharmony_ci		snd_pcm_unlock(pcm);
544d5ac70f0Sopenharmony_ci		return -EBADFD;
545d5ac70f0Sopenharmony_ci	case SND_PCM_STATE_PREPARED:
546d5ac70f0Sopenharmony_ci		if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
547d5ac70f0Sopenharmony_ci			if (!io->data->callback->drain) {
548d5ac70f0Sopenharmony_ci				err = snd_pcm_ioplug_start(pcm);
549d5ac70f0Sopenharmony_ci				if (err < 0)
550d5ac70f0Sopenharmony_ci					goto unlock;
551d5ac70f0Sopenharmony_ci			}
552d5ac70f0Sopenharmony_ci			io->data->state = SND_PCM_STATE_DRAINING;
553d5ac70f0Sopenharmony_ci		}
554d5ac70f0Sopenharmony_ci		break;
555d5ac70f0Sopenharmony_ci	case SND_PCM_STATE_RUNNING:
556d5ac70f0Sopenharmony_ci		io->data->state = SND_PCM_STATE_DRAINING;
557d5ac70f0Sopenharmony_ci		break;
558d5ac70f0Sopenharmony_ci	default:
559d5ac70f0Sopenharmony_ci		break;
560d5ac70f0Sopenharmony_ci	}
561d5ac70f0Sopenharmony_ci
562d5ac70f0Sopenharmony_ci	if (io->data->state == SND_PCM_STATE_DRAINING) {
563d5ac70f0Sopenharmony_ci		if (io->data->callback->drain) {
564d5ac70f0Sopenharmony_ci			snd_pcm_unlock(pcm); /* let plugin own locking */
565d5ac70f0Sopenharmony_ci			err = io->data->callback->drain(io->data);
566d5ac70f0Sopenharmony_ci			snd_pcm_lock(pcm);
567d5ac70f0Sopenharmony_ci		} else {
568d5ac70f0Sopenharmony_ci			err = ioplug_drain_via_poll(pcm);
569d5ac70f0Sopenharmony_ci		}
570d5ac70f0Sopenharmony_ci	}
571d5ac70f0Sopenharmony_ci
572d5ac70f0Sopenharmony_ci unlock:
573d5ac70f0Sopenharmony_ci	if (!err && io->data->state != SND_PCM_STATE_SETUP)
574d5ac70f0Sopenharmony_ci		snd_pcm_ioplug_drop(pcm);
575d5ac70f0Sopenharmony_ci	snd_pcm_unlock(pcm);
576d5ac70f0Sopenharmony_ci	return err;
577d5ac70f0Sopenharmony_ci}
578d5ac70f0Sopenharmony_ci
579d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_pause(snd_pcm_t *pcm, int enable)
580d5ac70f0Sopenharmony_ci{
581d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
582d5ac70f0Sopenharmony_ci	static const snd_pcm_state_t states[2] = {
583d5ac70f0Sopenharmony_ci		SND_PCM_STATE_RUNNING, SND_PCM_STATE_PAUSED
584d5ac70f0Sopenharmony_ci	};
585d5ac70f0Sopenharmony_ci	int prev, err;
586d5ac70f0Sopenharmony_ci
587d5ac70f0Sopenharmony_ci	prev = !enable;
588d5ac70f0Sopenharmony_ci	enable = !prev;
589d5ac70f0Sopenharmony_ci	if (io->data->state != states[prev])
590d5ac70f0Sopenharmony_ci		return -EBADFD;
591d5ac70f0Sopenharmony_ci	if (io->data->callback->pause) {
592d5ac70f0Sopenharmony_ci		err = io->data->callback->pause(io->data, enable);
593d5ac70f0Sopenharmony_ci		if (err < 0)
594d5ac70f0Sopenharmony_ci			return err;
595d5ac70f0Sopenharmony_ci	}
596d5ac70f0Sopenharmony_ci	io->data->state = states[enable];
597d5ac70f0Sopenharmony_ci	return 0;
598d5ac70f0Sopenharmony_ci}
599d5ac70f0Sopenharmony_ci
600d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_rewindable(snd_pcm_t *pcm)
601d5ac70f0Sopenharmony_ci{
602d5ac70f0Sopenharmony_ci	return snd_pcm_mmap_hw_rewindable(pcm);
603d5ac70f0Sopenharmony_ci}
604d5ac70f0Sopenharmony_ci
605d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
606d5ac70f0Sopenharmony_ci{
607d5ac70f0Sopenharmony_ci	snd_pcm_mmap_appl_backward(pcm, frames);
608d5ac70f0Sopenharmony_ci	return frames;
609d5ac70f0Sopenharmony_ci}
610d5ac70f0Sopenharmony_ci
611d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_forwardable(snd_pcm_t *pcm)
612d5ac70f0Sopenharmony_ci{
613d5ac70f0Sopenharmony_ci	return snd_pcm_mmap_avail(pcm);
614d5ac70f0Sopenharmony_ci}
615d5ac70f0Sopenharmony_ci
616d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
617d5ac70f0Sopenharmony_ci{
618d5ac70f0Sopenharmony_ci	snd_pcm_mmap_appl_forward(pcm, frames);
619d5ac70f0Sopenharmony_ci	return frames;
620d5ac70f0Sopenharmony_ci}
621d5ac70f0Sopenharmony_ci
622d5ac70f0Sopenharmony_ci/* need own locking */
623d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_resume(snd_pcm_t *pcm)
624d5ac70f0Sopenharmony_ci{
625d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
626d5ac70f0Sopenharmony_ci
627d5ac70f0Sopenharmony_ci	if (io->data->callback->resume)
628d5ac70f0Sopenharmony_ci		io->data->callback->resume(io->data);
629d5ac70f0Sopenharmony_ci	return 0;
630d5ac70f0Sopenharmony_ci}
631d5ac70f0Sopenharmony_ci
632d5ac70f0Sopenharmony_ci/* called in lock */
633d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t ioplug_priv_transfer_areas(snd_pcm_t *pcm,
634d5ac70f0Sopenharmony_ci						       const snd_pcm_channel_area_t *areas,
635d5ac70f0Sopenharmony_ci						       snd_pcm_uframes_t offset,
636d5ac70f0Sopenharmony_ci						       snd_pcm_uframes_t size)
637d5ac70f0Sopenharmony_ci{
638d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
639d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t result;
640d5ac70f0Sopenharmony_ci
641d5ac70f0Sopenharmony_ci	if (! size)
642d5ac70f0Sopenharmony_ci		return 0;
643d5ac70f0Sopenharmony_ci	if (io->data->callback->transfer)
644d5ac70f0Sopenharmony_ci		result = io->data->callback->transfer(io->data, areas, offset, size);
645d5ac70f0Sopenharmony_ci	else
646d5ac70f0Sopenharmony_ci		result = size;
647d5ac70f0Sopenharmony_ci	if (result > 0)
648d5ac70f0Sopenharmony_ci		snd_pcm_mmap_appl_forward(pcm, result);
649d5ac70f0Sopenharmony_ci	return result;
650d5ac70f0Sopenharmony_ci}
651d5ac70f0Sopenharmony_ci
652d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
653d5ac70f0Sopenharmony_ci{
654d5ac70f0Sopenharmony_ci	if (pcm->mmap_rw)
655d5ac70f0Sopenharmony_ci		return snd_pcm_mmap_writei(pcm, buffer, size);
656d5ac70f0Sopenharmony_ci	else {
657d5ac70f0Sopenharmony_ci		snd_pcm_channel_area_t areas[pcm->channels];
658d5ac70f0Sopenharmony_ci		snd_pcm_areas_from_buf(pcm, areas, (void*)buffer);
659d5ac70f0Sopenharmony_ci		return snd_pcm_write_areas(pcm, areas, 0, size,
660d5ac70f0Sopenharmony_ci					   ioplug_priv_transfer_areas);
661d5ac70f0Sopenharmony_ci	}
662d5ac70f0Sopenharmony_ci}
663d5ac70f0Sopenharmony_ci
664d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
665d5ac70f0Sopenharmony_ci{
666d5ac70f0Sopenharmony_ci	if (pcm->mmap_rw)
667d5ac70f0Sopenharmony_ci		return snd_pcm_mmap_writen(pcm, bufs, size);
668d5ac70f0Sopenharmony_ci	else {
669d5ac70f0Sopenharmony_ci		snd_pcm_channel_area_t areas[pcm->channels];
670d5ac70f0Sopenharmony_ci		snd_pcm_areas_from_bufs(pcm, areas, bufs);
671d5ac70f0Sopenharmony_ci		return snd_pcm_write_areas(pcm, areas, 0, size,
672d5ac70f0Sopenharmony_ci					   ioplug_priv_transfer_areas);
673d5ac70f0Sopenharmony_ci	}
674d5ac70f0Sopenharmony_ci}
675d5ac70f0Sopenharmony_ci
676d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
677d5ac70f0Sopenharmony_ci{
678d5ac70f0Sopenharmony_ci	if (pcm->mmap_rw)
679d5ac70f0Sopenharmony_ci		return snd_pcm_mmap_readi(pcm, buffer, size);
680d5ac70f0Sopenharmony_ci	else {
681d5ac70f0Sopenharmony_ci		snd_pcm_channel_area_t areas[pcm->channels];
682d5ac70f0Sopenharmony_ci		snd_pcm_areas_from_buf(pcm, areas, buffer);
683d5ac70f0Sopenharmony_ci		return snd_pcm_read_areas(pcm, areas, 0, size,
684d5ac70f0Sopenharmony_ci					  ioplug_priv_transfer_areas);
685d5ac70f0Sopenharmony_ci	}
686d5ac70f0Sopenharmony_ci}
687d5ac70f0Sopenharmony_ci
688d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
689d5ac70f0Sopenharmony_ci{
690d5ac70f0Sopenharmony_ci	if (pcm->mmap_rw)
691d5ac70f0Sopenharmony_ci		return snd_pcm_mmap_readn(pcm, bufs, size);
692d5ac70f0Sopenharmony_ci	else {
693d5ac70f0Sopenharmony_ci		snd_pcm_channel_area_t areas[pcm->channels];
694d5ac70f0Sopenharmony_ci		snd_pcm_areas_from_bufs(pcm, areas, bufs);
695d5ac70f0Sopenharmony_ci		return snd_pcm_read_areas(pcm, areas, 0, size,
696d5ac70f0Sopenharmony_ci					  ioplug_priv_transfer_areas);
697d5ac70f0Sopenharmony_ci	}
698d5ac70f0Sopenharmony_ci}
699d5ac70f0Sopenharmony_ci
700d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_mmap_begin_capture(snd_pcm_t *pcm,
701d5ac70f0Sopenharmony_ci					     const snd_pcm_channel_area_t **areas,
702d5ac70f0Sopenharmony_ci					     snd_pcm_uframes_t *offset,
703d5ac70f0Sopenharmony_ci					     snd_pcm_uframes_t *frames)
704d5ac70f0Sopenharmony_ci{
705d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
706d5ac70f0Sopenharmony_ci	int err;
707d5ac70f0Sopenharmony_ci
708d5ac70f0Sopenharmony_ci	err = __snd_pcm_mmap_begin_generic(pcm, areas, offset, frames);
709d5ac70f0Sopenharmony_ci	if (err < 0)
710d5ac70f0Sopenharmony_ci		return err;
711d5ac70f0Sopenharmony_ci
712d5ac70f0Sopenharmony_ci	if (io->data->callback->transfer &&
713d5ac70f0Sopenharmony_ci	    pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
714d5ac70f0Sopenharmony_ci	    pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) {
715d5ac70f0Sopenharmony_ci		snd_pcm_sframes_t result;
716d5ac70f0Sopenharmony_ci		result = io->data->callback->transfer(io->data, *areas, *offset, *frames);
717d5ac70f0Sopenharmony_ci		if (result < 0)
718d5ac70f0Sopenharmony_ci			return result;
719d5ac70f0Sopenharmony_ci	}
720d5ac70f0Sopenharmony_ci
721d5ac70f0Sopenharmony_ci	return err;
722d5ac70f0Sopenharmony_ci}
723d5ac70f0Sopenharmony_ci
724d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas,
725d5ac70f0Sopenharmony_ci				     snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames)
726d5ac70f0Sopenharmony_ci{
727d5ac70f0Sopenharmony_ci	if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
728d5ac70f0Sopenharmony_ci		return __snd_pcm_mmap_begin_generic(pcm, areas, offset, frames);
729d5ac70f0Sopenharmony_ci	return snd_pcm_ioplug_mmap_begin_capture(pcm, areas, offset, frames);
730d5ac70f0Sopenharmony_ci}
731d5ac70f0Sopenharmony_ci
732d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_mmap_commit(snd_pcm_t *pcm,
733d5ac70f0Sopenharmony_ci						    snd_pcm_uframes_t offset,
734d5ac70f0Sopenharmony_ci						    snd_pcm_uframes_t size)
735d5ac70f0Sopenharmony_ci{
736d5ac70f0Sopenharmony_ci	if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
737d5ac70f0Sopenharmony_ci	    pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
738d5ac70f0Sopenharmony_ci	    pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) {
739d5ac70f0Sopenharmony_ci		const snd_pcm_channel_area_t *areas;
740d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t ofs, frames = size;
741d5ac70f0Sopenharmony_ci
742d5ac70f0Sopenharmony_ci		__snd_pcm_mmap_begin_generic(pcm, &areas, &ofs, &frames);
743d5ac70f0Sopenharmony_ci		if (ofs != offset)
744d5ac70f0Sopenharmony_ci			return -EIO;
745d5ac70f0Sopenharmony_ci		return ioplug_priv_transfer_areas(pcm, areas, offset, frames);
746d5ac70f0Sopenharmony_ci	}
747d5ac70f0Sopenharmony_ci
748d5ac70f0Sopenharmony_ci	snd_pcm_mmap_appl_forward(pcm, size);
749d5ac70f0Sopenharmony_ci	return size;
750d5ac70f0Sopenharmony_ci}
751d5ac70f0Sopenharmony_ci
752d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_avail_update(snd_pcm_t *pcm)
753d5ac70f0Sopenharmony_ci{
754d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
755d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t avail;
756d5ac70f0Sopenharmony_ci
757d5ac70f0Sopenharmony_ci	snd_pcm_ioplug_hw_ptr_update(pcm);
758d5ac70f0Sopenharmony_ci	if (io->data->state == SND_PCM_STATE_XRUN)
759d5ac70f0Sopenharmony_ci		return -EPIPE;
760d5ac70f0Sopenharmony_ci
761d5ac70f0Sopenharmony_ci	avail = snd_pcm_mmap_avail(pcm);
762d5ac70f0Sopenharmony_ci	if (avail > io->avail_max)
763d5ac70f0Sopenharmony_ci		io->avail_max = avail;
764d5ac70f0Sopenharmony_ci	return (snd_pcm_sframes_t)avail;
765d5ac70f0Sopenharmony_ci}
766d5ac70f0Sopenharmony_ci
767d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_nonblock(snd_pcm_t *pcm, int nonblock)
768d5ac70f0Sopenharmony_ci{
769d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
770d5ac70f0Sopenharmony_ci
771d5ac70f0Sopenharmony_ci	io->data->nonblock = nonblock;
772d5ac70f0Sopenharmony_ci	return 0;
773d5ac70f0Sopenharmony_ci}
774d5ac70f0Sopenharmony_ci
775d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm)
776d5ac70f0Sopenharmony_ci{
777d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
778d5ac70f0Sopenharmony_ci	int err = 1;
779d5ac70f0Sopenharmony_ci
780d5ac70f0Sopenharmony_ci	if (io->data->callback->poll_descriptors_count) {
781d5ac70f0Sopenharmony_ci		snd_pcm_unlock(pcm); /* to avoid deadlock */
782d5ac70f0Sopenharmony_ci		err = io->data->callback->poll_descriptors_count(io->data);
783d5ac70f0Sopenharmony_ci		snd_pcm_lock(pcm);
784d5ac70f0Sopenharmony_ci	}
785d5ac70f0Sopenharmony_ci	return err;
786d5ac70f0Sopenharmony_ci}
787d5ac70f0Sopenharmony_ci
788d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
789d5ac70f0Sopenharmony_ci{
790d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
791d5ac70f0Sopenharmony_ci	int err;
792d5ac70f0Sopenharmony_ci
793d5ac70f0Sopenharmony_ci	if (io->data->callback->poll_descriptors) {
794d5ac70f0Sopenharmony_ci		snd_pcm_unlock(pcm); /* to avoid deadlock */
795d5ac70f0Sopenharmony_ci		err = io->data->callback->poll_descriptors(io->data, pfds, space);
796d5ac70f0Sopenharmony_ci		snd_pcm_lock(pcm);
797d5ac70f0Sopenharmony_ci		return err;
798d5ac70f0Sopenharmony_ci	}
799d5ac70f0Sopenharmony_ci	if (pcm->poll_fd < 0)
800d5ac70f0Sopenharmony_ci		return -EIO;
801d5ac70f0Sopenharmony_ci	if (space >= 1 && pfds) {
802d5ac70f0Sopenharmony_ci		pfds->fd = pcm->poll_fd;
803d5ac70f0Sopenharmony_ci		pfds->events = pcm->poll_events | POLLERR | POLLNVAL;
804d5ac70f0Sopenharmony_ci	} else {
805d5ac70f0Sopenharmony_ci		return 0;
806d5ac70f0Sopenharmony_ci	}
807d5ac70f0Sopenharmony_ci	return 1;
808d5ac70f0Sopenharmony_ci}
809d5ac70f0Sopenharmony_ci
810d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
811d5ac70f0Sopenharmony_ci{
812d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
813d5ac70f0Sopenharmony_ci	int err;
814d5ac70f0Sopenharmony_ci
815d5ac70f0Sopenharmony_ci	if (io->data->callback->poll_revents) {
816d5ac70f0Sopenharmony_ci		snd_pcm_unlock(pcm); /* to avoid deadlock */
817d5ac70f0Sopenharmony_ci		err = io->data->callback->poll_revents(io->data, pfds, nfds, revents);
818d5ac70f0Sopenharmony_ci		snd_pcm_lock(pcm);
819d5ac70f0Sopenharmony_ci	} else {
820d5ac70f0Sopenharmony_ci		*revents = pfds->revents;
821d5ac70f0Sopenharmony_ci		err = 0;
822d5ac70f0Sopenharmony_ci	}
823d5ac70f0Sopenharmony_ci	return err;
824d5ac70f0Sopenharmony_ci}
825d5ac70f0Sopenharmony_ci
826d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
827d5ac70f0Sopenharmony_ci{
828d5ac70f0Sopenharmony_ci	return 0;
829d5ac70f0Sopenharmony_ci}
830d5ac70f0Sopenharmony_ci
831d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
832d5ac70f0Sopenharmony_ci				int sig ATTRIBUTE_UNUSED,
833d5ac70f0Sopenharmony_ci				pid_t pid ATTRIBUTE_UNUSED)
834d5ac70f0Sopenharmony_ci{
835d5ac70f0Sopenharmony_ci	return -ENOSYS;
836d5ac70f0Sopenharmony_ci}
837d5ac70f0Sopenharmony_ci
838d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
839d5ac70f0Sopenharmony_ci{
840d5ac70f0Sopenharmony_ci	return 0;
841d5ac70f0Sopenharmony_ci}
842d5ac70f0Sopenharmony_ci
843d5ac70f0Sopenharmony_cistatic snd_pcm_chmap_query_t **snd_pcm_ioplug_query_chmaps(snd_pcm_t *pcm)
844d5ac70f0Sopenharmony_ci{
845d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
846d5ac70f0Sopenharmony_ci
847d5ac70f0Sopenharmony_ci	if (io->data->version >= 0x010002 &&
848d5ac70f0Sopenharmony_ci	    io->data->callback->query_chmaps)
849d5ac70f0Sopenharmony_ci		return io->data->callback->query_chmaps(io->data);
850d5ac70f0Sopenharmony_ci	return NULL;
851d5ac70f0Sopenharmony_ci}
852d5ac70f0Sopenharmony_ci
853d5ac70f0Sopenharmony_cistatic snd_pcm_chmap_t *snd_pcm_ioplug_get_chmap(snd_pcm_t *pcm)
854d5ac70f0Sopenharmony_ci{
855d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
856d5ac70f0Sopenharmony_ci
857d5ac70f0Sopenharmony_ci	if (io->data->version >= 0x010002 &&
858d5ac70f0Sopenharmony_ci	    io->data->callback->get_chmap)
859d5ac70f0Sopenharmony_ci		return io->data->callback->get_chmap(io->data);
860d5ac70f0Sopenharmony_ci	return NULL;
861d5ac70f0Sopenharmony_ci}
862d5ac70f0Sopenharmony_ci
863d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
864d5ac70f0Sopenharmony_ci{
865d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
866d5ac70f0Sopenharmony_ci
867d5ac70f0Sopenharmony_ci	if (io->data->version >= 0x010002 &&
868d5ac70f0Sopenharmony_ci	    io->data->callback->set_chmap)
869d5ac70f0Sopenharmony_ci		return io->data->callback->set_chmap(io->data, map);
870d5ac70f0Sopenharmony_ci	return -ENXIO;
871d5ac70f0Sopenharmony_ci}
872d5ac70f0Sopenharmony_ci
873d5ac70f0Sopenharmony_cistatic void snd_pcm_ioplug_dump(snd_pcm_t *pcm, snd_output_t *out)
874d5ac70f0Sopenharmony_ci{
875d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
876d5ac70f0Sopenharmony_ci
877d5ac70f0Sopenharmony_ci	if (io->data->callback->dump)
878d5ac70f0Sopenharmony_ci		io->data->callback->dump(io->data, out);
879d5ac70f0Sopenharmony_ci	else {
880d5ac70f0Sopenharmony_ci		if (io->data->name)
881d5ac70f0Sopenharmony_ci			snd_output_printf(out, "%s\n", io->data->name);
882d5ac70f0Sopenharmony_ci		else
883d5ac70f0Sopenharmony_ci			snd_output_printf(out, "IO-PCM Plugin\n");
884d5ac70f0Sopenharmony_ci		if (pcm->setup) {
885d5ac70f0Sopenharmony_ci			snd_output_printf(out, "Its setup is:\n");
886d5ac70f0Sopenharmony_ci			snd_pcm_dump_setup(pcm, out);
887d5ac70f0Sopenharmony_ci		}
888d5ac70f0Sopenharmony_ci	}
889d5ac70f0Sopenharmony_ci}
890d5ac70f0Sopenharmony_ci
891d5ac70f0Sopenharmony_cistatic void clear_io_params(ioplug_priv_t *io)
892d5ac70f0Sopenharmony_ci{
893d5ac70f0Sopenharmony_ci	int i;
894d5ac70f0Sopenharmony_ci	for (i = 0; i < SND_PCM_IOPLUG_HW_PARAMS; i++)
895d5ac70f0Sopenharmony_ci		snd_ext_parm_clear(&io->params[i]);
896d5ac70f0Sopenharmony_ci}
897d5ac70f0Sopenharmony_ci
898d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_close(snd_pcm_t *pcm)
899d5ac70f0Sopenharmony_ci{
900d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = pcm->private_data;
901d5ac70f0Sopenharmony_ci
902d5ac70f0Sopenharmony_ci	clear_io_params(io);
903d5ac70f0Sopenharmony_ci	if (io->data->callback->close)
904d5ac70f0Sopenharmony_ci		io->data->callback->close(io->data);
905d5ac70f0Sopenharmony_ci	free(io);
906d5ac70f0Sopenharmony_ci
907d5ac70f0Sopenharmony_ci	return 0;
908d5ac70f0Sopenharmony_ci}
909d5ac70f0Sopenharmony_ci
910d5ac70f0Sopenharmony_cistatic const snd_pcm_ops_t snd_pcm_ioplug_ops = {
911d5ac70f0Sopenharmony_ci	.close = snd_pcm_ioplug_close,
912d5ac70f0Sopenharmony_ci	.nonblock = snd_pcm_ioplug_nonblock,
913d5ac70f0Sopenharmony_ci	.async = snd_pcm_ioplug_async,
914d5ac70f0Sopenharmony_ci	.info = snd_pcm_ioplug_info,
915d5ac70f0Sopenharmony_ci	.hw_refine = snd_pcm_ioplug_hw_refine,
916d5ac70f0Sopenharmony_ci	.hw_params = snd_pcm_ioplug_hw_params,
917d5ac70f0Sopenharmony_ci	.hw_free = snd_pcm_ioplug_hw_free,
918d5ac70f0Sopenharmony_ci	.sw_params = snd_pcm_ioplug_sw_params,
919d5ac70f0Sopenharmony_ci	.channel_info = snd_pcm_ioplug_channel_info,
920d5ac70f0Sopenharmony_ci	.dump = snd_pcm_ioplug_dump,
921d5ac70f0Sopenharmony_ci	.mmap = snd_pcm_ioplug_mmap,
922d5ac70f0Sopenharmony_ci	.munmap = snd_pcm_ioplug_munmap,
923d5ac70f0Sopenharmony_ci	.query_chmaps = snd_pcm_ioplug_query_chmaps,
924d5ac70f0Sopenharmony_ci	.get_chmap = snd_pcm_ioplug_get_chmap,
925d5ac70f0Sopenharmony_ci	.set_chmap = snd_pcm_ioplug_set_chmap,
926d5ac70f0Sopenharmony_ci};
927d5ac70f0Sopenharmony_ci
928d5ac70f0Sopenharmony_cistatic const snd_pcm_fast_ops_t snd_pcm_ioplug_fast_ops = {
929d5ac70f0Sopenharmony_ci	.status = snd_pcm_ioplug_status,
930d5ac70f0Sopenharmony_ci	.prepare = snd_pcm_ioplug_prepare,
931d5ac70f0Sopenharmony_ci	.reset = snd_pcm_ioplug_reset,
932d5ac70f0Sopenharmony_ci	.start = snd_pcm_ioplug_start,
933d5ac70f0Sopenharmony_ci	.drop = snd_pcm_ioplug_drop,
934d5ac70f0Sopenharmony_ci	.drain = snd_pcm_ioplug_drain,
935d5ac70f0Sopenharmony_ci	.pause = snd_pcm_ioplug_pause,
936d5ac70f0Sopenharmony_ci	.state = snd_pcm_ioplug_state,
937d5ac70f0Sopenharmony_ci	.hwsync = snd_pcm_ioplug_hwsync,
938d5ac70f0Sopenharmony_ci	.delay = snd_pcm_ioplug_delay,
939d5ac70f0Sopenharmony_ci	.resume = snd_pcm_ioplug_resume,
940d5ac70f0Sopenharmony_ci	.link = NULL,
941d5ac70f0Sopenharmony_ci	.link_slaves = NULL,
942d5ac70f0Sopenharmony_ci	.unlink = NULL,
943d5ac70f0Sopenharmony_ci	.rewindable = snd_pcm_ioplug_rewindable,
944d5ac70f0Sopenharmony_ci	.rewind = snd_pcm_ioplug_rewind,
945d5ac70f0Sopenharmony_ci	.forwardable = snd_pcm_ioplug_forwardable,
946d5ac70f0Sopenharmony_ci	.forward = snd_pcm_ioplug_forward,
947d5ac70f0Sopenharmony_ci	.writei = snd_pcm_ioplug_writei,
948d5ac70f0Sopenharmony_ci	.writen = snd_pcm_ioplug_writen,
949d5ac70f0Sopenharmony_ci	.readi = snd_pcm_ioplug_readi,
950d5ac70f0Sopenharmony_ci	.readn = snd_pcm_ioplug_readn,
951d5ac70f0Sopenharmony_ci	.avail_update = snd_pcm_ioplug_avail_update,
952d5ac70f0Sopenharmony_ci	.mmap_commit = snd_pcm_ioplug_mmap_commit,
953d5ac70f0Sopenharmony_ci	.htimestamp = snd_pcm_generic_real_htimestamp,
954d5ac70f0Sopenharmony_ci	.poll_descriptors_count = snd_pcm_ioplug_poll_descriptors_count,
955d5ac70f0Sopenharmony_ci	.poll_descriptors = snd_pcm_ioplug_poll_descriptors,
956d5ac70f0Sopenharmony_ci	.poll_revents = snd_pcm_ioplug_poll_revents,
957d5ac70f0Sopenharmony_ci	.mmap_begin = snd_pcm_ioplug_mmap_begin,
958d5ac70f0Sopenharmony_ci};
959d5ac70f0Sopenharmony_ci
960d5ac70f0Sopenharmony_ci#endif /* !DOC_HIDDEN */
961d5ac70f0Sopenharmony_ci
962d5ac70f0Sopenharmony_ci/*
963d5ac70f0Sopenharmony_ci * Exported functions
964d5ac70f0Sopenharmony_ci */
965d5ac70f0Sopenharmony_ci
966d5ac70f0Sopenharmony_ci/*! \page pcm_external_plugins PCM External Plugin SDK
967d5ac70f0Sopenharmony_ci
968d5ac70f0Sopenharmony_ci\section pcm_ioplug External Plugin: I/O Plugin
969d5ac70f0Sopenharmony_ci
970d5ac70f0Sopenharmony_ciThe I/O-type plugin is a PCM plugin to work as the input or output terminal point,
971d5ac70f0Sopenharmony_cii.e. as a user-space PCM driver.
972d5ac70f0Sopenharmony_ci
973d5ac70f0Sopenharmony_ciThe new plugin is created via #snd_pcm_ioplug_create() function.
974d5ac70f0Sopenharmony_ciThe first argument is a pointer of the pluging information.  Some of
975d5ac70f0Sopenharmony_cithis struct must be initialized in prior to call
976d5ac70f0Sopenharmony_ci#snd_pcm_ioplug_create().  Then the function fills other fields in
977d5ac70f0Sopenharmony_cireturn.  The rest arguments, name, stream and mode, are usually
978d5ac70f0Sopenharmony_ciidentical with the values passed from the ALSA plugin constructor.
979d5ac70f0Sopenharmony_ci
980d5ac70f0Sopenharmony_ciThe following fields are mandatory: version, name, callback.
981d5ac70f0Sopenharmony_ciOtherfields are optional and should be initialized with zero.
982d5ac70f0Sopenharmony_ci
983d5ac70f0Sopenharmony_ciThe constant #SND_PCM_IOPLUG_VERSION must be passed to the version
984d5ac70f0Sopenharmony_cifield for the version check in alsa-lib.  A non-NULL ASCII string
985d5ac70f0Sopenharmony_cihas to be passed to the name field.  The callback field contains the
986d5ac70f0Sopenharmony_citable of callback functions for this plugin (defined as
987d5ac70f0Sopenharmony_ci#snd_pcm_ioplug_callback_t).
988d5ac70f0Sopenharmony_ci
989d5ac70f0Sopenharmony_ciflags field specifies the optional bit-flags.  poll_fd and poll_events
990d5ac70f0Sopenharmony_cispecify the poll file descriptor and the corresponding poll events
991d5ac70f0Sopenharmony_ci(POLLIN, POLLOUT) for the plugin.  If the plugin requires multiple
992d5ac70f0Sopenharmony_cipoll descriptors or poll descriptor(s) dynamically varying, set
993d5ac70f0Sopenharmony_cipoll_descriptors and poll_descriptors_count callbacks to the callback
994d5ac70f0Sopenharmony_citable.  Then the poll_fd and poll_events field are ignored.
995d5ac70f0Sopenharmony_ci
996d5ac70f0Sopenharmony_cimmap_rw specifies whether the plugin behaves in the pseudo mmap mode.
997d5ac70f0Sopenharmony_ciWhen this value is set to 1, the plugin creates always a local buffer
998d5ac70f0Sopenharmony_ciand performs read/write calls using this buffer as if it's mmapped.
999d5ac70f0Sopenharmony_ciThe address of local buffer can be obtained via
1000d5ac70f0Sopenharmony_ci#snd_pcm_ioplug_mmap_areas() function.
1001d5ac70f0Sopenharmony_ciWhen poll_fd, poll_events and mmap_rw fields are changed after
1002d5ac70f0Sopenharmony_ci#snd_pcm_ioplug_create(), call #snd_pcm_ioplug_reinit_status() to
1003d5ac70f0Sopenharmony_cireflect the changes.
1004d5ac70f0Sopenharmony_ci
1005d5ac70f0Sopenharmony_ciThe driver can set an arbitrary value (pointer) to private_data
1006d5ac70f0Sopenharmony_cifield to refer its own data in the callbacks.
1007d5ac70f0Sopenharmony_ci
1008d5ac70f0Sopenharmony_ciThe rest fields are filled by #snd_pcm_ioplug_create().  The pcm field
1009d5ac70f0Sopenharmony_ciis the resultant PCM handle.  The others are the current status of the
1010d5ac70f0Sopenharmony_ciPCM.
1011d5ac70f0Sopenharmony_ci
1012d5ac70f0Sopenharmony_ciThe callback functions in #snd_pcm_ioplug_callback_t define the real
1013d5ac70f0Sopenharmony_cibehavior of the driver.
1014d5ac70f0Sopenharmony_ciAt least, start, stop and pointer callbacks must be given.  Other
1015d5ac70f0Sopenharmony_cicallbacks are optional.  The start and stop callbacks are called when
1016d5ac70f0Sopenharmony_cithe PCM stream is started and stopped, repsectively.  The pointer
1017d5ac70f0Sopenharmony_cicallback returns the current DMA position, which may be called at any
1018d5ac70f0Sopenharmony_citime.
1019d5ac70f0Sopenharmony_ci
1020d5ac70f0Sopenharmony_ciThe transfer callback is called when any data transfer happens.  It
1021d5ac70f0Sopenharmony_cireceives the area array, offset and the size to transfer.  The area
1022d5ac70f0Sopenharmony_ciarray contains the array of snd_pcm_channel_area_t with the elements
1023d5ac70f0Sopenharmony_ciof number of channels.
1024d5ac70f0Sopenharmony_ci
1025d5ac70f0Sopenharmony_ciWhen the PCM is closed, close callback is called.  If the driver
1026d5ac70f0Sopenharmony_ciallocates any internal buffers, they should be released in this
1027d5ac70f0Sopenharmony_cicallback.  The hw_params and hw_free callbacks are called when
1028d5ac70f0Sopenharmony_cihw_params are set and reset, respectively.  Note that they may be
1029d5ac70f0Sopenharmony_cicalled multiple times according to the application.  Similarly,
1030d5ac70f0Sopenharmony_cisw_params callback is called when sw_params is set or changed.
1031d5ac70f0Sopenharmony_ci
1032d5ac70f0Sopenharmony_ciThe prepare, drain, pause and resume callbacks are called when
1033d5ac70f0Sopenharmony_ci#snd_pcm_prepare(), #snd_pcm_drain(), #snd_pcm_pause(), and
1034d5ac70f0Sopenharmony_ci#snd_pcm_resume() are called.  The poll_descriptors_count and
1035d5ac70f0Sopenharmony_cipoll_descriptors callbacks are used to return the multiple or dynamic
1036d5ac70f0Sopenharmony_cipoll descriptors as mentioned above.  The poll_revents callback is
1037d5ac70f0Sopenharmony_ciused to modify poll events.  If the driver needs to mangle the native
1038d5ac70f0Sopenharmony_cipoll events to proper poll events for PCM, you can do it in this
1039d5ac70f0Sopenharmony_cicallback.
1040d5ac70f0Sopenharmony_ci
1041d5ac70f0Sopenharmony_ciFinally, the dump callback is used to print the status of the plugin.
1042d5ac70f0Sopenharmony_ci
1043d5ac70f0Sopenharmony_ciNote that some callbacks (start, stop, pointer, transfer and pause)
1044d5ac70f0Sopenharmony_cimay be called inside the internal pthread mutex, and they shouldn't
1045d5ac70f0Sopenharmony_cicall the PCM functions again unnecessarily from the callback itself;
1046d5ac70f0Sopenharmony_ciotherwise it may lead to a deadlock.
1047d5ac70f0Sopenharmony_ci
1048d5ac70f0Sopenharmony_ciThe hw_params constraints can be defined via either
1049d5ac70f0Sopenharmony_ci#snd_pcm_ioplug_set_param_minmax() and #snd_pcm_ioplug_set_param_list()
1050d5ac70f0Sopenharmony_cifunctions after calling #snd_pcm_ioplug_create().
1051d5ac70f0Sopenharmony_ciThe former defines the minimal and maximal acceptable values for the
1052d5ac70f0Sopenharmony_cigiven hw_params parameter (SND_PCM_IOPLUG_HW_XXX).
1053d5ac70f0Sopenharmony_ciThis function can't be used for the format parameter.  The latter
1054d5ac70f0Sopenharmony_cifunction specifies the available parameter values as the list.
1055d5ac70f0Sopenharmony_ci
1056d5ac70f0Sopenharmony_ciTo clear the parameter constraints, call #snd_pcm_ioplug_params_reset() function.
1057d5ac70f0Sopenharmony_ci
1058d5ac70f0Sopenharmony_ci*/
1059d5ac70f0Sopenharmony_ci
1060d5ac70f0Sopenharmony_ci/**
1061d5ac70f0Sopenharmony_ci * \brief Create an ioplug instance
1062d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle
1063d5ac70f0Sopenharmony_ci * \param name name of PCM
1064d5ac70f0Sopenharmony_ci * \param stream stream direction
1065d5ac70f0Sopenharmony_ci * \param mode PCM open mode
1066d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code
1067d5ac70f0Sopenharmony_ci *
1068d5ac70f0Sopenharmony_ci * Creates the ioplug instance.
1069d5ac70f0Sopenharmony_ci *
1070d5ac70f0Sopenharmony_ci * The callback is the mandatory field of ioplug handle.  At least, start, stop and
1071d5ac70f0Sopenharmony_ci * pointer callbacks must be set before calling this function.
1072d5ac70f0Sopenharmony_ci *
1073d5ac70f0Sopenharmony_ci */
1074d5ac70f0Sopenharmony_ciint snd_pcm_ioplug_create(snd_pcm_ioplug_t *ioplug, const char *name,
1075d5ac70f0Sopenharmony_ci			  snd_pcm_stream_t stream, int mode)
1076d5ac70f0Sopenharmony_ci{
1077d5ac70f0Sopenharmony_ci	ioplug_priv_t *io;
1078d5ac70f0Sopenharmony_ci	int err;
1079d5ac70f0Sopenharmony_ci	snd_pcm_t *pcm;
1080d5ac70f0Sopenharmony_ci
1081d5ac70f0Sopenharmony_ci	assert(ioplug && ioplug->callback);
1082d5ac70f0Sopenharmony_ci	assert(ioplug->callback->start &&
1083d5ac70f0Sopenharmony_ci	       ioplug->callback->stop &&
1084d5ac70f0Sopenharmony_ci	       ioplug->callback->pointer);
1085d5ac70f0Sopenharmony_ci
1086d5ac70f0Sopenharmony_ci	/* We support 1.0.0 to current */
1087d5ac70f0Sopenharmony_ci	if (ioplug->version < 0x010000 ||
1088d5ac70f0Sopenharmony_ci	    ioplug->version > SND_PCM_IOPLUG_VERSION) {
1089d5ac70f0Sopenharmony_ci		SNDERR("ioplug: Plugin version mismatch: 0x%x",
1090d5ac70f0Sopenharmony_ci		       ioplug->version);
1091d5ac70f0Sopenharmony_ci		return -ENXIO;
1092d5ac70f0Sopenharmony_ci	}
1093d5ac70f0Sopenharmony_ci
1094d5ac70f0Sopenharmony_ci	io = calloc(1, sizeof(*io));
1095d5ac70f0Sopenharmony_ci	if (! io)
1096d5ac70f0Sopenharmony_ci		return -ENOMEM;
1097d5ac70f0Sopenharmony_ci
1098d5ac70f0Sopenharmony_ci	io->data = ioplug;
1099d5ac70f0Sopenharmony_ci	ioplug->state = SND_PCM_STATE_OPEN;
1100d5ac70f0Sopenharmony_ci	ioplug->stream = stream;
1101d5ac70f0Sopenharmony_ci
1102d5ac70f0Sopenharmony_ci	err = snd_pcm_new(&pcm, SND_PCM_TYPE_IOPLUG, name, stream, mode);
1103d5ac70f0Sopenharmony_ci	if (err < 0) {
1104d5ac70f0Sopenharmony_ci		free(io);
1105d5ac70f0Sopenharmony_ci		return err;
1106d5ac70f0Sopenharmony_ci	}
1107d5ac70f0Sopenharmony_ci
1108d5ac70f0Sopenharmony_ci	ioplug->pcm = pcm;
1109d5ac70f0Sopenharmony_ci	pcm->ops = &snd_pcm_ioplug_ops;
1110d5ac70f0Sopenharmony_ci	pcm->fast_ops = &snd_pcm_ioplug_fast_ops;
1111d5ac70f0Sopenharmony_ci	pcm->private_data = io;
1112d5ac70f0Sopenharmony_ci
1113d5ac70f0Sopenharmony_ci	snd_pcm_set_hw_ptr(pcm, &ioplug->hw_ptr, -1, 0);
1114d5ac70f0Sopenharmony_ci	snd_pcm_set_appl_ptr(pcm, &ioplug->appl_ptr, -1, 0);
1115d5ac70f0Sopenharmony_ci
1116d5ac70f0Sopenharmony_ci	snd_pcm_ioplug_reinit_status(ioplug);
1117d5ac70f0Sopenharmony_ci
1118d5ac70f0Sopenharmony_ci	return 0;
1119d5ac70f0Sopenharmony_ci}
1120d5ac70f0Sopenharmony_ci
1121d5ac70f0Sopenharmony_ci/**
1122d5ac70f0Sopenharmony_ci * \brief Delete the ioplug instance
1123d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle
1124d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code
1125d5ac70f0Sopenharmony_ci */
1126d5ac70f0Sopenharmony_ciint snd_pcm_ioplug_delete(snd_pcm_ioplug_t *ioplug)
1127d5ac70f0Sopenharmony_ci{
1128d5ac70f0Sopenharmony_ci	return snd_pcm_close(ioplug->pcm);
1129d5ac70f0Sopenharmony_ci}
1130d5ac70f0Sopenharmony_ci
1131d5ac70f0Sopenharmony_ci
1132d5ac70f0Sopenharmony_ci/**
1133d5ac70f0Sopenharmony_ci * \brief Reset ioplug parameters
1134d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle
1135d5ac70f0Sopenharmony_ci *
1136d5ac70f0Sopenharmony_ci * Resets the all parameters for the given ioplug handle.
1137d5ac70f0Sopenharmony_ci */
1138d5ac70f0Sopenharmony_civoid snd_pcm_ioplug_params_reset(snd_pcm_ioplug_t *ioplug)
1139d5ac70f0Sopenharmony_ci{
1140d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = ioplug->pcm->private_data;
1141d5ac70f0Sopenharmony_ci	clear_io_params(io);
1142d5ac70f0Sopenharmony_ci}
1143d5ac70f0Sopenharmony_ci
1144d5ac70f0Sopenharmony_ci/**
1145d5ac70f0Sopenharmony_ci * \brief Set parameter as the list
1146d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle
1147d5ac70f0Sopenharmony_ci * \param type parameter type
1148d5ac70f0Sopenharmony_ci * \param num_list number of available values
1149d5ac70f0Sopenharmony_ci * \param list the list of available values
1150d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code
1151d5ac70f0Sopenharmony_ci *
1152d5ac70f0Sopenharmony_ci * Sets the parameter as the list.
1153d5ac70f0Sopenharmony_ci * The available values of the given parameter type is restricted to the ones of the given list.
1154d5ac70f0Sopenharmony_ci */
1155d5ac70f0Sopenharmony_ciint snd_pcm_ioplug_set_param_list(snd_pcm_ioplug_t *ioplug, int type, unsigned int num_list, const unsigned int *list)
1156d5ac70f0Sopenharmony_ci{
1157d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = ioplug->pcm->private_data;
1158d5ac70f0Sopenharmony_ci	if (type < 0 || type >= SND_PCM_IOPLUG_HW_PARAMS) {
1159d5ac70f0Sopenharmony_ci		SNDERR("IOPLUG: invalid parameter type %d", type);
1160d5ac70f0Sopenharmony_ci		return -EINVAL;
1161d5ac70f0Sopenharmony_ci	}
1162d5ac70f0Sopenharmony_ci	if (type == SND_PCM_IOPLUG_HW_PERIODS)
1163d5ac70f0Sopenharmony_ci		io->params[type].integer = 1;
1164d5ac70f0Sopenharmony_ci	return snd_ext_parm_set_list(&io->params[type], num_list, list);
1165d5ac70f0Sopenharmony_ci}
1166d5ac70f0Sopenharmony_ci
1167d5ac70f0Sopenharmony_ci/**
1168d5ac70f0Sopenharmony_ci * \brief Set parameter as the min/max values
1169d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle
1170d5ac70f0Sopenharmony_ci * \param type parameter type
1171d5ac70f0Sopenharmony_ci * \param min the minimum value
1172d5ac70f0Sopenharmony_ci * \param max the maximum value
1173d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code
1174d5ac70f0Sopenharmony_ci *
1175d5ac70f0Sopenharmony_ci * Sets the parameter as the min/max values.
1176d5ac70f0Sopenharmony_ci * The available values of the given parameter type is restricted between the given
1177d5ac70f0Sopenharmony_ci * minimum and maximum values.
1178d5ac70f0Sopenharmony_ci */
1179d5ac70f0Sopenharmony_ciint snd_pcm_ioplug_set_param_minmax(snd_pcm_ioplug_t *ioplug, int type, unsigned int min, unsigned int max)
1180d5ac70f0Sopenharmony_ci{
1181d5ac70f0Sopenharmony_ci	ioplug_priv_t *io = ioplug->pcm->private_data;
1182d5ac70f0Sopenharmony_ci	if (type < 0 || type >= SND_PCM_IOPLUG_HW_PARAMS) {
1183d5ac70f0Sopenharmony_ci		SNDERR("IOPLUG: invalid parameter type %d", type);
1184d5ac70f0Sopenharmony_ci		return -EINVAL;
1185d5ac70f0Sopenharmony_ci	}
1186d5ac70f0Sopenharmony_ci	if (type == SND_PCM_IOPLUG_HW_ACCESS || type == SND_PCM_IOPLUG_HW_FORMAT) {
1187d5ac70f0Sopenharmony_ci		SNDERR("IOPLUG: invalid parameter type %d", type);
1188d5ac70f0Sopenharmony_ci		return -EINVAL;
1189d5ac70f0Sopenharmony_ci	}
1190d5ac70f0Sopenharmony_ci	if (type == SND_PCM_IOPLUG_HW_PERIODS)
1191d5ac70f0Sopenharmony_ci		io->params[type].integer = 1;
1192d5ac70f0Sopenharmony_ci	return snd_ext_parm_set_minmax(&io->params[type], min, max);
1193d5ac70f0Sopenharmony_ci}
1194d5ac70f0Sopenharmony_ci
1195d5ac70f0Sopenharmony_ci/**
1196d5ac70f0Sopenharmony_ci * \brief Reinitialize the poll and mmap status
1197d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle
1198d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code
1199d5ac70f0Sopenharmony_ci *
1200d5ac70f0Sopenharmony_ci * Reinitializes the poll and the mmap status of the PCM.
1201d5ac70f0Sopenharmony_ci * Call this function to propagate the status change in the ioplug instance to
1202d5ac70f0Sopenharmony_ci * its PCM internals.
1203d5ac70f0Sopenharmony_ci */
1204d5ac70f0Sopenharmony_ciint snd_pcm_ioplug_reinit_status(snd_pcm_ioplug_t *ioplug)
1205d5ac70f0Sopenharmony_ci{
1206d5ac70f0Sopenharmony_ci	ioplug->pcm->poll_fd = ioplug->poll_fd;
1207d5ac70f0Sopenharmony_ci	ioplug->pcm->poll_events = ioplug->poll_events;
1208d5ac70f0Sopenharmony_ci	if (ioplug->flags & SND_PCM_IOPLUG_FLAG_MONOTONIC)
1209d5ac70f0Sopenharmony_ci		ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC;
1210d5ac70f0Sopenharmony_ci	else
1211d5ac70f0Sopenharmony_ci		ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
1212d5ac70f0Sopenharmony_ci	ioplug->pcm->mmap_rw = ioplug->mmap_rw;
1213d5ac70f0Sopenharmony_ci	return 0;
1214d5ac70f0Sopenharmony_ci}
1215d5ac70f0Sopenharmony_ci
1216d5ac70f0Sopenharmony_ci/**
1217d5ac70f0Sopenharmony_ci * \brief Get mmap area of ioplug
1218d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle
1219d5ac70f0Sopenharmony_ci * \return the mmap channel areas if available, or NULL
1220d5ac70f0Sopenharmony_ci *
1221d5ac70f0Sopenharmony_ci * Returns the mmap channel areas if available.  When mmap_rw field is not set,
1222d5ac70f0Sopenharmony_ci * this function always returns NULL.
1223d5ac70f0Sopenharmony_ci */
1224d5ac70f0Sopenharmony_ciconst snd_pcm_channel_area_t *snd_pcm_ioplug_mmap_areas(snd_pcm_ioplug_t *ioplug)
1225d5ac70f0Sopenharmony_ci{
1226d5ac70f0Sopenharmony_ci	if (ioplug->mmap_rw)
1227d5ac70f0Sopenharmony_ci		return snd_pcm_mmap_areas(ioplug->pcm);
1228d5ac70f0Sopenharmony_ci	return NULL;
1229d5ac70f0Sopenharmony_ci}
1230d5ac70f0Sopenharmony_ci
1231d5ac70f0Sopenharmony_ci/**
1232d5ac70f0Sopenharmony_ci * \brief Change the ioplug PCM status
1233d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle
1234d5ac70f0Sopenharmony_ci * \param state the PCM status
1235d5ac70f0Sopenharmony_ci * \return zero if successful or a negative error code
1236d5ac70f0Sopenharmony_ci *
1237d5ac70f0Sopenharmony_ci * Changes the PCM status of the ioplug to the given value.
1238d5ac70f0Sopenharmony_ci * This function can be used for external plugins to notify the status
1239d5ac70f0Sopenharmony_ci * change, e.g. XRUN.
1240d5ac70f0Sopenharmony_ci */
1241d5ac70f0Sopenharmony_ciint snd_pcm_ioplug_set_state(snd_pcm_ioplug_t *ioplug, snd_pcm_state_t state)
1242d5ac70f0Sopenharmony_ci{
1243d5ac70f0Sopenharmony_ci	ioplug->state = state;
1244d5ac70f0Sopenharmony_ci	return 0;
1245d5ac70f0Sopenharmony_ci}
1246d5ac70f0Sopenharmony_ci
1247d5ac70f0Sopenharmony_ci/**
1248d5ac70f0Sopenharmony_ci * \brief Get the available frames. This function can be used to calculate the
1249d5ac70f0Sopenharmony_ci * the available frames before calling #snd_pcm_avail_update()
1250d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle
1251d5ac70f0Sopenharmony_ci * \param hw_ptr hardware pointer in frames
1252d5ac70f0Sopenharmony_ci * \param appl_ptr application pointer in frames
1253d5ac70f0Sopenharmony_ci * \return available frames for the application
1254d5ac70f0Sopenharmony_ci */
1255d5ac70f0Sopenharmony_cisnd_pcm_uframes_t snd_pcm_ioplug_avail(const snd_pcm_ioplug_t * const ioplug,
1256d5ac70f0Sopenharmony_ci				       const snd_pcm_uframes_t hw_ptr,
1257d5ac70f0Sopenharmony_ci				       const snd_pcm_uframes_t appl_ptr)
1258d5ac70f0Sopenharmony_ci{
1259d5ac70f0Sopenharmony_ci	return __snd_pcm_avail(ioplug->pcm, hw_ptr, appl_ptr);
1260d5ac70f0Sopenharmony_ci}
1261d5ac70f0Sopenharmony_ci
1262d5ac70f0Sopenharmony_ci/**
1263d5ac70f0Sopenharmony_ci * \brief Get the available frames. This function can be used to calculate the
1264d5ac70f0Sopenharmony_ci * the available frames before calling #snd_pcm_avail_update()
1265d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle
1266d5ac70f0Sopenharmony_ci * \param hw_ptr hardware pointer in frames
1267d5ac70f0Sopenharmony_ci * \param appl_ptr application pointer in frames
1268d5ac70f0Sopenharmony_ci * \return available frames for the hardware
1269d5ac70f0Sopenharmony_ci */
1270d5ac70f0Sopenharmony_cisnd_pcm_uframes_t snd_pcm_ioplug_hw_avail(const snd_pcm_ioplug_t * const ioplug,
1271d5ac70f0Sopenharmony_ci					  const snd_pcm_uframes_t hw_ptr,
1272d5ac70f0Sopenharmony_ci					  const snd_pcm_uframes_t appl_ptr)
1273d5ac70f0Sopenharmony_ci{
1274d5ac70f0Sopenharmony_ci	/* available data/space which can be transferred by the user
1275d5ac70f0Sopenharmony_ci	 * application
1276d5ac70f0Sopenharmony_ci	 */
1277d5ac70f0Sopenharmony_ci	const snd_pcm_uframes_t user_avail = snd_pcm_ioplug_avail(ioplug,
1278d5ac70f0Sopenharmony_ci								  hw_ptr,
1279d5ac70f0Sopenharmony_ci								  appl_ptr);
1280d5ac70f0Sopenharmony_ci
1281d5ac70f0Sopenharmony_ci	if (user_avail > ioplug->pcm->buffer_size) {
1282d5ac70f0Sopenharmony_ci		/* there was an Xrun */
1283d5ac70f0Sopenharmony_ci		return 0;
1284d5ac70f0Sopenharmony_ci	}
1285d5ac70f0Sopenharmony_ci	/* available data/space which can be transferred by the DMA */
1286d5ac70f0Sopenharmony_ci	return ioplug->pcm->buffer_size - user_avail;
1287d5ac70f0Sopenharmony_ci}
1288