1d5ac70f0Sopenharmony_ci/**
2d5ac70f0Sopenharmony_ci * \file pcm/pcm_plugin.c
3d5ac70f0Sopenharmony_ci * \ingroup PCM
4d5ac70f0Sopenharmony_ci * \brief PCM Interface
5d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz>
6d5ac70f0Sopenharmony_ci * \author Abramo Bagnara <abramo@alsa-project.org>
7d5ac70f0Sopenharmony_ci * \date 2000-2001
8d5ac70f0Sopenharmony_ci */
9d5ac70f0Sopenharmony_ci/*
10d5ac70f0Sopenharmony_ci *  PCM - Common plugin code
11d5ac70f0Sopenharmony_ci *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
12d5ac70f0Sopenharmony_ci *
13d5ac70f0Sopenharmony_ci *
14d5ac70f0Sopenharmony_ci *   This library is free software; you can redistribute it and/or modify
15d5ac70f0Sopenharmony_ci *   it under the terms of the GNU Lesser General Public License as
16d5ac70f0Sopenharmony_ci *   published by the Free Software Foundation; either version 2.1 of
17d5ac70f0Sopenharmony_ci *   the License, or (at your option) any later version.
18d5ac70f0Sopenharmony_ci *
19d5ac70f0Sopenharmony_ci *   This program is distributed in the hope that it will be useful,
20d5ac70f0Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
21d5ac70f0Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22d5ac70f0Sopenharmony_ci *   GNU Lesser General Public License for more details.
23d5ac70f0Sopenharmony_ci *
24d5ac70f0Sopenharmony_ci *   You should have received a copy of the GNU Lesser General Public
25d5ac70f0Sopenharmony_ci *   License along with this library; if not, write to the Free Software
26d5ac70f0Sopenharmony_ci *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
27d5ac70f0Sopenharmony_ci *
28d5ac70f0Sopenharmony_ci */
29d5ac70f0Sopenharmony_ci
30d5ac70f0Sopenharmony_ci/*!
31d5ac70f0Sopenharmony_ci
32d5ac70f0Sopenharmony_ci\page pcm_plugins PCM (digital audio) plugins
33d5ac70f0Sopenharmony_ci
34d5ac70f0Sopenharmony_ciPCM plugins extends functionality and features of PCM devices.
35d5ac70f0Sopenharmony_ciThe plugins take care about various sample conversions, sample
36d5ac70f0Sopenharmony_cicopying among channels and so on.
37d5ac70f0Sopenharmony_ci
38d5ac70f0Sopenharmony_ci\section pcm_plugins_slave Slave definition
39d5ac70f0Sopenharmony_ci
40d5ac70f0Sopenharmony_ciThe slave plugin can be specified directly with a string or the definition
41d5ac70f0Sopenharmony_cican be entered inside a compound configuration node. Some restrictions can
42d5ac70f0Sopenharmony_cibe also specified (like static rate or count of channels).
43d5ac70f0Sopenharmony_ci
44d5ac70f0Sopenharmony_ci\code
45d5ac70f0Sopenharmony_cipcm_slave.NAME {
46d5ac70f0Sopenharmony_ci	pcm STR		# PCM name
47d5ac70f0Sopenharmony_ci	# or
48d5ac70f0Sopenharmony_ci	pcm { }		# PCM definition
49d5ac70f0Sopenharmony_ci	format STR	# Format or "unchanged"
50d5ac70f0Sopenharmony_ci	channels INT	# Count of channels or "unchanged" string
51d5ac70f0Sopenharmony_ci	rate INT	# Rate in Hz or "unchanged" string
52d5ac70f0Sopenharmony_ci	period_time INT	# Period time in us or "unchanged" string
53d5ac70f0Sopenharmony_ci	buffer_time INT # Buffer time in us or "unchanged" string
54d5ac70f0Sopenharmony_ci}
55d5ac70f0Sopenharmony_ci\endcode
56d5ac70f0Sopenharmony_ci
57d5ac70f0Sopenharmony_ciExample:
58d5ac70f0Sopenharmony_ci
59d5ac70f0Sopenharmony_ci\code
60d5ac70f0Sopenharmony_cipcm_slave.slave_rate44100Hz {
61d5ac70f0Sopenharmony_ci	pcm "hw:0,0"
62d5ac70f0Sopenharmony_ci	rate 44100
63d5ac70f0Sopenharmony_ci}
64d5ac70f0Sopenharmony_ci
65d5ac70f0Sopenharmony_cipcm.rate44100Hz {
66d5ac70f0Sopenharmony_ci	type plug
67d5ac70f0Sopenharmony_ci	slave slave_rate44100Hz
68d5ac70f0Sopenharmony_ci}
69d5ac70f0Sopenharmony_ci\endcode
70d5ac70f0Sopenharmony_ci
71d5ac70f0Sopenharmony_ciThe equivalent configuration (in one compound):
72d5ac70f0Sopenharmony_ci
73d5ac70f0Sopenharmony_ci\code
74d5ac70f0Sopenharmony_cipcm.rate44100Hz {
75d5ac70f0Sopenharmony_ci	type plug
76d5ac70f0Sopenharmony_ci	slave {
77d5ac70f0Sopenharmony_ci		pcm "hw:0,0"
78d5ac70f0Sopenharmony_ci		rate 44100
79d5ac70f0Sopenharmony_ci	}
80d5ac70f0Sopenharmony_ci}
81d5ac70f0Sopenharmony_ci\endcode
82d5ac70f0Sopenharmony_ci
83d5ac70f0Sopenharmony_ci*/
84d5ac70f0Sopenharmony_ci
85d5ac70f0Sopenharmony_ci#include "pcm_local.h"
86d5ac70f0Sopenharmony_ci#include "pcm_plugin.h"
87d5ac70f0Sopenharmony_ci#include <limits.h>
88d5ac70f0Sopenharmony_ci
89d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
90d5ac70f0Sopenharmony_ci
91d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t
92d5ac70f0Sopenharmony_cisnd_pcm_plugin_undo_read(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
93d5ac70f0Sopenharmony_ci			 const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED,
94d5ac70f0Sopenharmony_ci			 snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED,
95d5ac70f0Sopenharmony_ci			 snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED,
96d5ac70f0Sopenharmony_ci			 snd_pcm_uframes_t slave_undo_size ATTRIBUTE_UNUSED)
97d5ac70f0Sopenharmony_ci{
98d5ac70f0Sopenharmony_ci	return -EIO;
99d5ac70f0Sopenharmony_ci}
100d5ac70f0Sopenharmony_ci
101d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t
102d5ac70f0Sopenharmony_cisnd_pcm_plugin_undo_write(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
103d5ac70f0Sopenharmony_ci			  const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED,
104d5ac70f0Sopenharmony_ci			  snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED,
105d5ac70f0Sopenharmony_ci			  snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED,
106d5ac70f0Sopenharmony_ci			  snd_pcm_uframes_t slave_undo_size ATTRIBUTE_UNUSED)
107d5ac70f0Sopenharmony_ci{
108d5ac70f0Sopenharmony_ci	return -EIO;
109d5ac70f0Sopenharmony_ci}
110d5ac70f0Sopenharmony_ci
111d5ac70f0Sopenharmony_cisnd_pcm_sframes_t
112d5ac70f0Sopenharmony_cisnd_pcm_plugin_undo_read_generic(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
113d5ac70f0Sopenharmony_ci				 const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED,
114d5ac70f0Sopenharmony_ci				 snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED,
115d5ac70f0Sopenharmony_ci				 snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED,
116d5ac70f0Sopenharmony_ci				 snd_pcm_uframes_t slave_undo_size)
117d5ac70f0Sopenharmony_ci{
118d5ac70f0Sopenharmony_ci	return slave_undo_size;
119d5ac70f0Sopenharmony_ci}
120d5ac70f0Sopenharmony_ci
121d5ac70f0Sopenharmony_cisnd_pcm_sframes_t
122d5ac70f0Sopenharmony_cisnd_pcm_plugin_undo_write_generic(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
123d5ac70f0Sopenharmony_ci				  const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED,
124d5ac70f0Sopenharmony_ci				  snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED,
125d5ac70f0Sopenharmony_ci				  snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED,
126d5ac70f0Sopenharmony_ci				  snd_pcm_uframes_t slave_undo_size)
127d5ac70f0Sopenharmony_ci{
128d5ac70f0Sopenharmony_ci	return slave_undo_size;
129d5ac70f0Sopenharmony_ci}
130d5ac70f0Sopenharmony_ci
131d5ac70f0Sopenharmony_civoid snd_pcm_plugin_init(snd_pcm_plugin_t *plugin)
132d5ac70f0Sopenharmony_ci{
133d5ac70f0Sopenharmony_ci	memset(plugin, 0, sizeof(snd_pcm_plugin_t));
134d5ac70f0Sopenharmony_ci	plugin->undo_read = snd_pcm_plugin_undo_read;
135d5ac70f0Sopenharmony_ci	plugin->undo_write = snd_pcm_plugin_undo_write;
136d5ac70f0Sopenharmony_ci}
137d5ac70f0Sopenharmony_ci
138d5ac70f0Sopenharmony_cistatic int snd_pcm_plugin_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
139d5ac70f0Sopenharmony_ci{
140d5ac70f0Sopenharmony_ci	snd_pcm_plugin_t *plugin = pcm->private_data;
141d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t sd;
142d5ac70f0Sopenharmony_ci	int err = snd_pcm_delay(plugin->gen.slave, &sd);
143d5ac70f0Sopenharmony_ci	if (err < 0)
144d5ac70f0Sopenharmony_ci		return err;
145d5ac70f0Sopenharmony_ci	*delayp = sd;
146d5ac70f0Sopenharmony_ci	return 0;
147d5ac70f0Sopenharmony_ci}
148d5ac70f0Sopenharmony_ci
149d5ac70f0Sopenharmony_cistatic int snd_pcm_plugin_call_init_cb(snd_pcm_t *pcm, snd_pcm_plugin_t *plugin)
150d5ac70f0Sopenharmony_ci{
151d5ac70f0Sopenharmony_ci	snd_pcm_t *slave = plugin->gen.slave;
152d5ac70f0Sopenharmony_ci	int err;
153d5ac70f0Sopenharmony_ci
154d5ac70f0Sopenharmony_ci	assert(pcm->boundary == slave->boundary);
155d5ac70f0Sopenharmony_ci	*pcm->hw.ptr = *slave->hw.ptr;
156d5ac70f0Sopenharmony_ci	*pcm->appl.ptr = *slave->appl.ptr;
157d5ac70f0Sopenharmony_ci	if (plugin->init) {
158d5ac70f0Sopenharmony_ci		err = plugin->init(pcm);
159d5ac70f0Sopenharmony_ci		if (err < 0)
160d5ac70f0Sopenharmony_ci			return err;
161d5ac70f0Sopenharmony_ci	}
162d5ac70f0Sopenharmony_ci	return 0;
163d5ac70f0Sopenharmony_ci}
164d5ac70f0Sopenharmony_ci
165d5ac70f0Sopenharmony_cistatic int snd_pcm_plugin_prepare(snd_pcm_t *pcm)
166d5ac70f0Sopenharmony_ci{
167d5ac70f0Sopenharmony_ci	snd_pcm_plugin_t *plugin = pcm->private_data;
168d5ac70f0Sopenharmony_ci	int err;
169d5ac70f0Sopenharmony_ci	err = snd_pcm_prepare(plugin->gen.slave);
170d5ac70f0Sopenharmony_ci	if (err < 0)
171d5ac70f0Sopenharmony_ci		return err;
172d5ac70f0Sopenharmony_ci	return snd_pcm_plugin_call_init_cb(pcm, plugin);
173d5ac70f0Sopenharmony_ci}
174d5ac70f0Sopenharmony_ci
175d5ac70f0Sopenharmony_cistatic int snd_pcm_plugin_reset(snd_pcm_t *pcm)
176d5ac70f0Sopenharmony_ci{
177d5ac70f0Sopenharmony_ci	snd_pcm_plugin_t *plugin = pcm->private_data;
178d5ac70f0Sopenharmony_ci	int err;
179d5ac70f0Sopenharmony_ci	err = snd_pcm_reset(plugin->gen.slave);
180d5ac70f0Sopenharmony_ci	if (err < 0)
181d5ac70f0Sopenharmony_ci		return err;
182d5ac70f0Sopenharmony_ci	return snd_pcm_plugin_call_init_cb(pcm, plugin);
183d5ac70f0Sopenharmony_ci}
184d5ac70f0Sopenharmony_ci
185d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_plugin_rewindable(snd_pcm_t *pcm)
186d5ac70f0Sopenharmony_ci{
187d5ac70f0Sopenharmony_ci	return snd_pcm_mmap_hw_rewindable(pcm);
188d5ac70f0Sopenharmony_ci}
189d5ac70f0Sopenharmony_ci
190d5ac70f0Sopenharmony_cisnd_pcm_sframes_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
191d5ac70f0Sopenharmony_ci{
192d5ac70f0Sopenharmony_ci	snd_pcm_plugin_t *plugin = pcm->private_data;
193d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t n = snd_pcm_plugin_rewindable(pcm);
194d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t sframes;
195d5ac70f0Sopenharmony_ci
196d5ac70f0Sopenharmony_ci	if ((snd_pcm_uframes_t)n < frames)
197d5ac70f0Sopenharmony_ci		frames = n;
198d5ac70f0Sopenharmony_ci	if (frames == 0)
199d5ac70f0Sopenharmony_ci		return 0;
200d5ac70f0Sopenharmony_ci
201d5ac70f0Sopenharmony_ci        sframes = frames;
202d5ac70f0Sopenharmony_ci	sframes = snd_pcm_rewind(plugin->gen.slave, sframes);
203d5ac70f0Sopenharmony_ci	if (sframes < 0)
204d5ac70f0Sopenharmony_ci		return sframes;
205d5ac70f0Sopenharmony_ci	snd_pcm_mmap_appl_backward(pcm, (snd_pcm_uframes_t) sframes);
206d5ac70f0Sopenharmony_ci	return (snd_pcm_sframes_t) sframes;
207d5ac70f0Sopenharmony_ci}
208d5ac70f0Sopenharmony_ci
209d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_plugin_forwardable(snd_pcm_t *pcm)
210d5ac70f0Sopenharmony_ci{
211d5ac70f0Sopenharmony_ci	return snd_pcm_mmap_avail(pcm);
212d5ac70f0Sopenharmony_ci}
213d5ac70f0Sopenharmony_ci
214d5ac70f0Sopenharmony_cisnd_pcm_sframes_t snd_pcm_plugin_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
215d5ac70f0Sopenharmony_ci{
216d5ac70f0Sopenharmony_ci	snd_pcm_plugin_t *plugin = pcm->private_data;
217d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t n = snd_pcm_plugin_forwardable(pcm);
218d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t sframes;
219d5ac70f0Sopenharmony_ci
220d5ac70f0Sopenharmony_ci	if ((snd_pcm_uframes_t)n < frames)
221d5ac70f0Sopenharmony_ci		frames = n;
222d5ac70f0Sopenharmony_ci	if (frames == 0)
223d5ac70f0Sopenharmony_ci		return 0;
224d5ac70f0Sopenharmony_ci
225d5ac70f0Sopenharmony_ci        sframes = frames;
226d5ac70f0Sopenharmony_ci	sframes = INTERNAL(snd_pcm_forward)(plugin->gen.slave, sframes);
227d5ac70f0Sopenharmony_ci	if (sframes < 0)
228d5ac70f0Sopenharmony_ci		return sframes;
229d5ac70f0Sopenharmony_ci	snd_pcm_mmap_appl_forward(pcm, (snd_pcm_uframes_t) frames);
230d5ac70f0Sopenharmony_ci	return (snd_pcm_sframes_t) frames;
231d5ac70f0Sopenharmony_ci}
232d5ac70f0Sopenharmony_ci
233d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_plugin_write_areas(snd_pcm_t *pcm,
234d5ac70f0Sopenharmony_ci						    const snd_pcm_channel_area_t *areas,
235d5ac70f0Sopenharmony_ci						    snd_pcm_uframes_t offset,
236d5ac70f0Sopenharmony_ci						    snd_pcm_uframes_t size)
237d5ac70f0Sopenharmony_ci{
238d5ac70f0Sopenharmony_ci	snd_pcm_plugin_t *plugin = pcm->private_data;
239d5ac70f0Sopenharmony_ci	snd_pcm_t *slave = plugin->gen.slave;
240d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t xfer = 0;
241d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t result;
242d5ac70f0Sopenharmony_ci	int err;
243d5ac70f0Sopenharmony_ci
244d5ac70f0Sopenharmony_ci	while (size > 0) {
245d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t frames = size;
246d5ac70f0Sopenharmony_ci		const snd_pcm_channel_area_t *slave_areas;
247d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t slave_offset;
248d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t slave_frames = ULONG_MAX;
249d5ac70f0Sopenharmony_ci
250d5ac70f0Sopenharmony_ci		result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
251d5ac70f0Sopenharmony_ci		if (result < 0) {
252d5ac70f0Sopenharmony_ci			err = result;
253d5ac70f0Sopenharmony_ci			goto error;
254d5ac70f0Sopenharmony_ci		}
255d5ac70f0Sopenharmony_ci		if (slave_frames == 0)
256d5ac70f0Sopenharmony_ci			break;
257d5ac70f0Sopenharmony_ci		frames = plugin->write(pcm, areas, offset, frames,
258d5ac70f0Sopenharmony_ci				       slave_areas, slave_offset, &slave_frames);
259d5ac70f0Sopenharmony_ci		if (CHECK_SANITY(slave_frames > snd_pcm_mmap_playback_avail(slave))) {
260d5ac70f0Sopenharmony_ci			SNDMSG("write overflow %ld > %ld", slave_frames,
261d5ac70f0Sopenharmony_ci			       snd_pcm_mmap_playback_avail(slave));
262d5ac70f0Sopenharmony_ci			err = -EPIPE;
263d5ac70f0Sopenharmony_ci			goto error;
264d5ac70f0Sopenharmony_ci		}
265d5ac70f0Sopenharmony_ci		result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
266d5ac70f0Sopenharmony_ci		if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) {
267d5ac70f0Sopenharmony_ci			snd_pcm_sframes_t res;
268d5ac70f0Sopenharmony_ci			res = plugin->undo_write(pcm, slave_areas, slave_offset + result, slave_frames, slave_frames - result);
269d5ac70f0Sopenharmony_ci			if (res < 0) {
270d5ac70f0Sopenharmony_ci				err = res;
271d5ac70f0Sopenharmony_ci				goto error;
272d5ac70f0Sopenharmony_ci			}
273d5ac70f0Sopenharmony_ci			frames -= res;
274d5ac70f0Sopenharmony_ci		}
275d5ac70f0Sopenharmony_ci		if (result <= 0) {
276d5ac70f0Sopenharmony_ci			err = result;
277d5ac70f0Sopenharmony_ci			goto error;
278d5ac70f0Sopenharmony_ci		}
279d5ac70f0Sopenharmony_ci		snd_pcm_mmap_appl_forward(pcm, frames);
280d5ac70f0Sopenharmony_ci		offset += frames;
281d5ac70f0Sopenharmony_ci		xfer += frames;
282d5ac70f0Sopenharmony_ci		size -= frames;
283d5ac70f0Sopenharmony_ci	}
284d5ac70f0Sopenharmony_ci	return (snd_pcm_sframes_t)xfer;
285d5ac70f0Sopenharmony_ci
286d5ac70f0Sopenharmony_ci error:
287d5ac70f0Sopenharmony_ci	return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
288d5ac70f0Sopenharmony_ci}
289d5ac70f0Sopenharmony_ci
290d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm,
291d5ac70f0Sopenharmony_ci						   const snd_pcm_channel_area_t *areas,
292d5ac70f0Sopenharmony_ci						   snd_pcm_uframes_t offset,
293d5ac70f0Sopenharmony_ci						   snd_pcm_uframes_t size)
294d5ac70f0Sopenharmony_ci{
295d5ac70f0Sopenharmony_ci	snd_pcm_plugin_t *plugin = pcm->private_data;
296d5ac70f0Sopenharmony_ci	snd_pcm_t *slave = plugin->gen.slave;
297d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t xfer = 0;
298d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t result;
299d5ac70f0Sopenharmony_ci	int err;
300d5ac70f0Sopenharmony_ci
301d5ac70f0Sopenharmony_ci	while (size > 0) {
302d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t frames = size;
303d5ac70f0Sopenharmony_ci		const snd_pcm_channel_area_t *slave_areas;
304d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t slave_offset;
305d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t slave_frames = ULONG_MAX;
306d5ac70f0Sopenharmony_ci
307d5ac70f0Sopenharmony_ci		result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
308d5ac70f0Sopenharmony_ci		if (result < 0) {
309d5ac70f0Sopenharmony_ci			err = result;
310d5ac70f0Sopenharmony_ci			goto error;
311d5ac70f0Sopenharmony_ci		}
312d5ac70f0Sopenharmony_ci		if (slave_frames == 0)
313d5ac70f0Sopenharmony_ci			break;
314d5ac70f0Sopenharmony_ci		frames = (plugin->read)(pcm, areas, offset, frames,
315d5ac70f0Sopenharmony_ci				      slave_areas, slave_offset, &slave_frames);
316d5ac70f0Sopenharmony_ci		if (CHECK_SANITY(slave_frames > snd_pcm_mmap_capture_avail(slave))) {
317d5ac70f0Sopenharmony_ci			SNDMSG("read overflow %ld > %ld", slave_frames,
318d5ac70f0Sopenharmony_ci			       snd_pcm_mmap_playback_avail(slave));
319d5ac70f0Sopenharmony_ci			err = -EPIPE;
320d5ac70f0Sopenharmony_ci			goto error;
321d5ac70f0Sopenharmony_ci		}
322d5ac70f0Sopenharmony_ci		result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
323d5ac70f0Sopenharmony_ci		if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) {
324d5ac70f0Sopenharmony_ci			snd_pcm_sframes_t res;
325d5ac70f0Sopenharmony_ci
326d5ac70f0Sopenharmony_ci			res = plugin->undo_read(slave, areas, offset, frames, slave_frames - result);
327d5ac70f0Sopenharmony_ci			if (res < 0) {
328d5ac70f0Sopenharmony_ci				err = res;
329d5ac70f0Sopenharmony_ci				goto error;
330d5ac70f0Sopenharmony_ci			}
331d5ac70f0Sopenharmony_ci			frames -= res;
332d5ac70f0Sopenharmony_ci		}
333d5ac70f0Sopenharmony_ci		if (result <= 0) {
334d5ac70f0Sopenharmony_ci			err = result;
335d5ac70f0Sopenharmony_ci			goto error;
336d5ac70f0Sopenharmony_ci		}
337d5ac70f0Sopenharmony_ci		snd_pcm_mmap_appl_forward(pcm, frames);
338d5ac70f0Sopenharmony_ci		offset += frames;
339d5ac70f0Sopenharmony_ci		xfer += frames;
340d5ac70f0Sopenharmony_ci		size -= frames;
341d5ac70f0Sopenharmony_ci	}
342d5ac70f0Sopenharmony_ci	return (snd_pcm_sframes_t)xfer;
343d5ac70f0Sopenharmony_ci
344d5ac70f0Sopenharmony_ci error:
345d5ac70f0Sopenharmony_ci	return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
346d5ac70f0Sopenharmony_ci}
347d5ac70f0Sopenharmony_ci
348d5ac70f0Sopenharmony_ci
349d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t
350d5ac70f0Sopenharmony_cisnd_pcm_plugin_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
351d5ac70f0Sopenharmony_ci{
352d5ac70f0Sopenharmony_ci	snd_pcm_channel_area_t areas[pcm->channels];
353d5ac70f0Sopenharmony_ci	snd_pcm_areas_from_buf(pcm, areas, (void*)buffer);
354d5ac70f0Sopenharmony_ci	return snd_pcm_write_areas(pcm, areas, 0, size,
355d5ac70f0Sopenharmony_ci				   snd_pcm_plugin_write_areas);
356d5ac70f0Sopenharmony_ci}
357d5ac70f0Sopenharmony_ci
358d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t
359d5ac70f0Sopenharmony_cisnd_pcm_plugin_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
360d5ac70f0Sopenharmony_ci{
361d5ac70f0Sopenharmony_ci	snd_pcm_channel_area_t areas[pcm->channels];
362d5ac70f0Sopenharmony_ci	snd_pcm_areas_from_bufs(pcm, areas, bufs);
363d5ac70f0Sopenharmony_ci	return snd_pcm_write_areas(pcm, areas, 0, size,
364d5ac70f0Sopenharmony_ci				   snd_pcm_plugin_write_areas);
365d5ac70f0Sopenharmony_ci}
366d5ac70f0Sopenharmony_ci
367d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t
368d5ac70f0Sopenharmony_cisnd_pcm_plugin_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
369d5ac70f0Sopenharmony_ci{
370d5ac70f0Sopenharmony_ci	snd_pcm_channel_area_t areas[pcm->channels];
371d5ac70f0Sopenharmony_ci	snd_pcm_areas_from_buf(pcm, areas, buffer);
372d5ac70f0Sopenharmony_ci	return snd_pcm_read_areas(pcm, areas, 0, size,
373d5ac70f0Sopenharmony_ci				  snd_pcm_plugin_read_areas);
374d5ac70f0Sopenharmony_ci}
375d5ac70f0Sopenharmony_ci
376d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t
377d5ac70f0Sopenharmony_cisnd_pcm_plugin_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
378d5ac70f0Sopenharmony_ci{
379d5ac70f0Sopenharmony_ci	snd_pcm_channel_area_t areas[pcm->channels];
380d5ac70f0Sopenharmony_ci	snd_pcm_areas_from_bufs(pcm, areas, bufs);
381d5ac70f0Sopenharmony_ci	return snd_pcm_read_areas(pcm, areas, 0, size,
382d5ac70f0Sopenharmony_ci				  snd_pcm_plugin_read_areas);
383d5ac70f0Sopenharmony_ci}
384d5ac70f0Sopenharmony_ci
385d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t
386d5ac70f0Sopenharmony_cisnd_pcm_plugin_mmap_commit(snd_pcm_t *pcm,
387d5ac70f0Sopenharmony_ci			   snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
388d5ac70f0Sopenharmony_ci			   snd_pcm_uframes_t size)
389d5ac70f0Sopenharmony_ci{
390d5ac70f0Sopenharmony_ci	snd_pcm_plugin_t *plugin = pcm->private_data;
391d5ac70f0Sopenharmony_ci	snd_pcm_t *slave = plugin->gen.slave;
392d5ac70f0Sopenharmony_ci	const snd_pcm_channel_area_t *areas;
393d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t appl_offset;
394d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t slave_size;
395d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t xfer;
396d5ac70f0Sopenharmony_ci	int err;
397d5ac70f0Sopenharmony_ci
398d5ac70f0Sopenharmony_ci	if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
399d5ac70f0Sopenharmony_ci		snd_pcm_mmap_appl_forward(pcm, size);
400d5ac70f0Sopenharmony_ci		return size;
401d5ac70f0Sopenharmony_ci	}
402d5ac70f0Sopenharmony_ci	slave_size = snd_pcm_avail_update(slave);
403d5ac70f0Sopenharmony_ci	if (slave_size < 0)
404d5ac70f0Sopenharmony_ci		return slave_size;
405d5ac70f0Sopenharmony_ci	areas = snd_pcm_mmap_areas(pcm);
406d5ac70f0Sopenharmony_ci	appl_offset = snd_pcm_mmap_offset(pcm);
407d5ac70f0Sopenharmony_ci	xfer = 0;
408d5ac70f0Sopenharmony_ci	while (size > 0 && slave_size > 0) {
409d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t frames = size;
410d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t cont = pcm->buffer_size - appl_offset;
411d5ac70f0Sopenharmony_ci		const snd_pcm_channel_area_t *slave_areas;
412d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t slave_offset;
413d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t slave_frames = ULONG_MAX;
414d5ac70f0Sopenharmony_ci		snd_pcm_sframes_t result;
415d5ac70f0Sopenharmony_ci
416d5ac70f0Sopenharmony_ci		result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
417d5ac70f0Sopenharmony_ci		if (result < 0) {
418d5ac70f0Sopenharmony_ci			err = result;
419d5ac70f0Sopenharmony_ci			goto error;
420d5ac70f0Sopenharmony_ci		}
421d5ac70f0Sopenharmony_ci		if (frames > cont)
422d5ac70f0Sopenharmony_ci			frames = cont;
423d5ac70f0Sopenharmony_ci		frames = plugin->write(pcm, areas, appl_offset, frames,
424d5ac70f0Sopenharmony_ci				       slave_areas, slave_offset, &slave_frames);
425d5ac70f0Sopenharmony_ci		result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
426d5ac70f0Sopenharmony_ci		if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) {
427d5ac70f0Sopenharmony_ci			snd_pcm_sframes_t res;
428d5ac70f0Sopenharmony_ci
429d5ac70f0Sopenharmony_ci			res = plugin->undo_write(pcm, slave_areas, slave_offset + result, slave_frames, slave_frames - result);
430d5ac70f0Sopenharmony_ci			if (res < 0) {
431d5ac70f0Sopenharmony_ci				err = res;
432d5ac70f0Sopenharmony_ci				goto error;
433d5ac70f0Sopenharmony_ci			}
434d5ac70f0Sopenharmony_ci			frames -= res;
435d5ac70f0Sopenharmony_ci		}
436d5ac70f0Sopenharmony_ci		if (result <= 0) {
437d5ac70f0Sopenharmony_ci			err = result;
438d5ac70f0Sopenharmony_ci			goto error;
439d5ac70f0Sopenharmony_ci		}
440d5ac70f0Sopenharmony_ci		snd_pcm_mmap_appl_forward(pcm, frames);
441d5ac70f0Sopenharmony_ci		if (frames == cont)
442d5ac70f0Sopenharmony_ci			appl_offset = 0;
443d5ac70f0Sopenharmony_ci		else
444d5ac70f0Sopenharmony_ci			appl_offset += result;
445d5ac70f0Sopenharmony_ci		size -= frames;
446d5ac70f0Sopenharmony_ci		slave_size -= frames;
447d5ac70f0Sopenharmony_ci		xfer += frames;
448d5ac70f0Sopenharmony_ci	}
449d5ac70f0Sopenharmony_ci	if (CHECK_SANITY(size)) {
450d5ac70f0Sopenharmony_ci		SNDMSG("short commit: %ld", size);
451d5ac70f0Sopenharmony_ci		return -EPIPE;
452d5ac70f0Sopenharmony_ci	}
453d5ac70f0Sopenharmony_ci	return xfer;
454d5ac70f0Sopenharmony_ci
455d5ac70f0Sopenharmony_ci error:
456d5ac70f0Sopenharmony_ci	return xfer > 0 ? xfer : err;
457d5ac70f0Sopenharmony_ci}
458d5ac70f0Sopenharmony_ci
459d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t
460d5ac70f0Sopenharmony_cisnd_pcm_plugin_sync_hw_ptr_capture(snd_pcm_t *pcm,
461d5ac70f0Sopenharmony_ci				   snd_pcm_sframes_t slave_size)
462d5ac70f0Sopenharmony_ci{
463d5ac70f0Sopenharmony_ci	snd_pcm_plugin_t *plugin = pcm->private_data;
464d5ac70f0Sopenharmony_ci	snd_pcm_t *slave = plugin->gen.slave;
465d5ac70f0Sopenharmony_ci	const snd_pcm_channel_area_t *areas;
466d5ac70f0Sopenharmony_ci	snd_pcm_uframes_t xfer, hw_offset, size;
467d5ac70f0Sopenharmony_ci	int err;
468d5ac70f0Sopenharmony_ci
469d5ac70f0Sopenharmony_ci	xfer = snd_pcm_mmap_capture_avail(pcm);
470d5ac70f0Sopenharmony_ci	size = pcm->buffer_size - xfer;
471d5ac70f0Sopenharmony_ci	areas = snd_pcm_mmap_areas(pcm);
472d5ac70f0Sopenharmony_ci	hw_offset = snd_pcm_mmap_hw_offset(pcm);
473d5ac70f0Sopenharmony_ci	while (size > 0 && slave_size > 0) {
474d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t frames = size;
475d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset;
476d5ac70f0Sopenharmony_ci		const snd_pcm_channel_area_t *slave_areas;
477d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t slave_offset;
478d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t slave_frames = ULONG_MAX;
479d5ac70f0Sopenharmony_ci		snd_pcm_sframes_t result;
480d5ac70f0Sopenharmony_ci		/* As mentioned in the ALSA API (see pcm/pcm.c:942):
481d5ac70f0Sopenharmony_ci		 * The function #snd_pcm_avail_update()
482d5ac70f0Sopenharmony_ci		 * have to be called before any mmap begin+commit operation.
483d5ac70f0Sopenharmony_ci		 * Otherwise the snd_pcm_areas_copy will not called a second time.
484d5ac70f0Sopenharmony_ci		 * But this is needed, if the ring buffer wrap is reached and
485d5ac70f0Sopenharmony_ci		 * there is more data available.
486d5ac70f0Sopenharmony_ci		 */
487d5ac70f0Sopenharmony_ci		slave_size = snd_pcm_avail_update(slave);
488d5ac70f0Sopenharmony_ci		result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
489d5ac70f0Sopenharmony_ci		if (result < 0) {
490d5ac70f0Sopenharmony_ci			err = result;
491d5ac70f0Sopenharmony_ci			goto error;
492d5ac70f0Sopenharmony_ci		}
493d5ac70f0Sopenharmony_ci		if (frames > cont)
494d5ac70f0Sopenharmony_ci			frames = cont;
495d5ac70f0Sopenharmony_ci		frames = (plugin->read)(pcm, areas, hw_offset, frames,
496d5ac70f0Sopenharmony_ci					slave_areas, slave_offset, &slave_frames);
497d5ac70f0Sopenharmony_ci		result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
498d5ac70f0Sopenharmony_ci		if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) {
499d5ac70f0Sopenharmony_ci			snd_pcm_sframes_t res;
500d5ac70f0Sopenharmony_ci			res = plugin->undo_read(slave, areas, hw_offset, frames, slave_frames - result);
501d5ac70f0Sopenharmony_ci			if (res < 0) {
502d5ac70f0Sopenharmony_ci				err = res;
503d5ac70f0Sopenharmony_ci				goto error;
504d5ac70f0Sopenharmony_ci			}
505d5ac70f0Sopenharmony_ci			frames -= res;
506d5ac70f0Sopenharmony_ci		}
507d5ac70f0Sopenharmony_ci		if (result <= 0) {
508d5ac70f0Sopenharmony_ci			err = result;
509d5ac70f0Sopenharmony_ci			goto error;
510d5ac70f0Sopenharmony_ci		}
511d5ac70f0Sopenharmony_ci		snd_pcm_mmap_hw_forward(pcm, frames);
512d5ac70f0Sopenharmony_ci		if (frames == cont)
513d5ac70f0Sopenharmony_ci			hw_offset = 0;
514d5ac70f0Sopenharmony_ci		else
515d5ac70f0Sopenharmony_ci			hw_offset += frames;
516d5ac70f0Sopenharmony_ci		size -= frames;
517d5ac70f0Sopenharmony_ci		slave_size -= slave_frames;
518d5ac70f0Sopenharmony_ci		xfer += frames;
519d5ac70f0Sopenharmony_ci	}
520d5ac70f0Sopenharmony_ci	return (snd_pcm_sframes_t)xfer;
521d5ac70f0Sopenharmony_cierror:
522d5ac70f0Sopenharmony_ci	return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
523d5ac70f0Sopenharmony_ci}
524d5ac70f0Sopenharmony_ci
525d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_plugin_sync_hw_ptr(snd_pcm_t *pcm,
526d5ac70f0Sopenharmony_ci						    snd_pcm_uframes_t slave_hw_ptr,
527d5ac70f0Sopenharmony_ci						    snd_pcm_sframes_t slave_size)
528d5ac70f0Sopenharmony_ci{
529d5ac70f0Sopenharmony_ci	if (pcm->stream == SND_PCM_STREAM_CAPTURE &&
530d5ac70f0Sopenharmony_ci	    pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
531d5ac70f0Sopenharmony_ci	    pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED)
532d5ac70f0Sopenharmony_ci		return snd_pcm_plugin_sync_hw_ptr_capture(pcm, slave_size);
533d5ac70f0Sopenharmony_ci        *pcm->hw.ptr = slave_hw_ptr;
534d5ac70f0Sopenharmony_ci        return slave_size;
535d5ac70f0Sopenharmony_ci}
536d5ac70f0Sopenharmony_ci
537d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
538d5ac70f0Sopenharmony_ci{
539d5ac70f0Sopenharmony_ci	snd_pcm_plugin_t *plugin = pcm->private_data;
540d5ac70f0Sopenharmony_ci	snd_pcm_t *slave = plugin->gen.slave;
541d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t slave_size;
542d5ac70f0Sopenharmony_ci
543d5ac70f0Sopenharmony_ci	slave_size = snd_pcm_avail_update(slave);
544d5ac70f0Sopenharmony_ci	return snd_pcm_plugin_sync_hw_ptr(pcm, *slave->hw.ptr, slave_size);
545d5ac70f0Sopenharmony_ci}
546d5ac70f0Sopenharmony_ci
547d5ac70f0Sopenharmony_cistatic int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
548d5ac70f0Sopenharmony_ci{
549d5ac70f0Sopenharmony_ci	snd_pcm_plugin_t *plugin = pcm->private_data;
550d5ac70f0Sopenharmony_ci	snd_pcm_sframes_t err, diff;
551d5ac70f0Sopenharmony_ci
552d5ac70f0Sopenharmony_ci	err = snd_pcm_status(plugin->gen.slave, status);
553d5ac70f0Sopenharmony_ci	if (err < 0)
554d5ac70f0Sopenharmony_ci		return err;
555d5ac70f0Sopenharmony_ci	snd_pcm_plugin_sync_hw_ptr(pcm, status->hw_ptr, status->avail);
556d5ac70f0Sopenharmony_ci	/*
557d5ac70f0Sopenharmony_ci	 * For capture stream, the situation is more complicated, because
558d5ac70f0Sopenharmony_ci	 * snd_pcm_plugin_avail_update() commits the data to the slave pcm.
559d5ac70f0Sopenharmony_ci	 * It means that the slave appl_ptr is updated. Calculate diff and
560d5ac70f0Sopenharmony_ci	 * update the delay and avail.
561d5ac70f0Sopenharmony_ci	 *
562d5ac70f0Sopenharmony_ci	 * This resolves the data inconsistency for immediate calls:
563d5ac70f0Sopenharmony_ci	 *    snd_pcm_avail_update()
564d5ac70f0Sopenharmony_ci	 *    snd_pcm_status()
565d5ac70f0Sopenharmony_ci	 */
566d5ac70f0Sopenharmony_ci	if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
567d5ac70f0Sopenharmony_ci		diff = pcm_frame_diff(status->appl_ptr, *pcm->appl.ptr, pcm->boundary);
568d5ac70f0Sopenharmony_ci		status->appl_ptr = *pcm->appl.ptr;
569d5ac70f0Sopenharmony_ci		status->avail += diff;
570d5ac70f0Sopenharmony_ci		status->delay += diff;
571d5ac70f0Sopenharmony_ci	} else {
572d5ac70f0Sopenharmony_ci		assert(status->appl_ptr == *pcm->appl.ptr);
573d5ac70f0Sopenharmony_ci	}
574d5ac70f0Sopenharmony_ci	return 0;
575d5ac70f0Sopenharmony_ci}
576d5ac70f0Sopenharmony_ci
577d5ac70f0Sopenharmony_ciint snd_pcm_plugin_may_wait_for_avail_min_conv(
578d5ac70f0Sopenharmony_ci				snd_pcm_t *pcm,
579d5ac70f0Sopenharmony_ci				snd_pcm_uframes_t avail,
580d5ac70f0Sopenharmony_ci				snd_pcm_uframes_t (*conv)(snd_pcm_t *, snd_pcm_uframes_t))
581d5ac70f0Sopenharmony_ci{
582d5ac70f0Sopenharmony_ci	if (pcm->stream == SND_PCM_STREAM_CAPTURE &&
583d5ac70f0Sopenharmony_ci	    pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
584d5ac70f0Sopenharmony_ci	    pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) {
585d5ac70f0Sopenharmony_ci		/* mmap access on capture device already consumes data from
586d5ac70f0Sopenharmony_ci		 * slave in avail_update operation. Entering snd_pcm_wait after
587d5ac70f0Sopenharmony_ci		 * having already consumed some fragments leads to waiting for
588d5ac70f0Sopenharmony_ci		 * too long time, as slave will unnecessarily wait for avail_min
589d5ac70f0Sopenharmony_ci		 * condition reached again. To avoid unnecessary wait times we
590d5ac70f0Sopenharmony_ci		 * adapt the avail_min threshold on slave dynamically. Just
591d5ac70f0Sopenharmony_ci		 * modifying slave->avail_min as a shortcut and lightweight
592d5ac70f0Sopenharmony_ci		 * solution does not work for all slave plugin types and in
593d5ac70f0Sopenharmony_ci		 * addition it will not propagate the change through all
594d5ac70f0Sopenharmony_ci		 * downstream plugins, so we have to use the sw_params API.
595d5ac70f0Sopenharmony_ci		 * note: reading fragmental parts from slave will only happen
596d5ac70f0Sopenharmony_ci		 * in case
597d5ac70f0Sopenharmony_ci		 * a) the slave can provide contineous hw_ptr between periods
598d5ac70f0Sopenharmony_ci		 * b) avail_min does not match one slave_period
599d5ac70f0Sopenharmony_ci		 */
600d5ac70f0Sopenharmony_ci		snd_pcm_generic_t *generic = pcm->private_data;
601d5ac70f0Sopenharmony_ci		/*
602d5ac70f0Sopenharmony_ci		 * do not use snd_pcm_plugin_t pointer here
603d5ac70f0Sopenharmony_ci		 * this code is used from the generic plugins, too
604d5ac70f0Sopenharmony_ci		 */
605d5ac70f0Sopenharmony_ci		snd_pcm_t *slave = generic->slave;
606d5ac70f0Sopenharmony_ci		snd_pcm_uframes_t needed_slave_avail_min;
607d5ac70f0Sopenharmony_ci		snd_pcm_sframes_t available;
608d5ac70f0Sopenharmony_ci
609d5ac70f0Sopenharmony_ci		/* update, as it might have changed. This will also call
610d5ac70f0Sopenharmony_ci		 * avail_update on slave and also can return error
611d5ac70f0Sopenharmony_ci		 */
612d5ac70f0Sopenharmony_ci		available = snd_pcm_avail_update(pcm);
613d5ac70f0Sopenharmony_ci		if (available < 0)
614d5ac70f0Sopenharmony_ci			return 0;
615d5ac70f0Sopenharmony_ci
616d5ac70f0Sopenharmony_ci		if ((snd_pcm_uframes_t)available >= pcm->avail_min)
617d5ac70f0Sopenharmony_ci			/* don't wait at all. As we can't configure avail_min
618d5ac70f0Sopenharmony_ci			 * of slave to 0 return here
619d5ac70f0Sopenharmony_ci			 */
620d5ac70f0Sopenharmony_ci			return 0;
621d5ac70f0Sopenharmony_ci
622d5ac70f0Sopenharmony_ci		needed_slave_avail_min = pcm->avail_min - available;
623d5ac70f0Sopenharmony_ci
624d5ac70f0Sopenharmony_ci		/* proportional adaption if rate converter is in place..
625d5ac70f0Sopenharmony_ci		 * Can happen only on built-in rate plugin.
626d5ac70f0Sopenharmony_ci		 * This code is also used by extplug, but extplug does not allow to alter the sampling rate.
627d5ac70f0Sopenharmony_ci		 */
628d5ac70f0Sopenharmony_ci		if (conv)
629d5ac70f0Sopenharmony_ci			needed_slave_avail_min = conv(pcm, needed_slave_avail_min);
630d5ac70f0Sopenharmony_ci
631d5ac70f0Sopenharmony_ci		if (slave->avail_min != needed_slave_avail_min) {
632d5ac70f0Sopenharmony_ci			snd_pcm_sw_params_t *swparams;
633d5ac70f0Sopenharmony_ci			snd_pcm_sw_params_alloca(&swparams);
634d5ac70f0Sopenharmony_ci			/* pray that changing sw_params while running is
635d5ac70f0Sopenharmony_ci			 * properly implemented in all downstream plugins...
636d5ac70f0Sopenharmony_ci			 * it's legal but not commonly used.
637d5ac70f0Sopenharmony_ci			 */
638d5ac70f0Sopenharmony_ci			snd_pcm_sw_params_current(slave, swparams);
639d5ac70f0Sopenharmony_ci			/* snd_pcm_sw_params_set_avail_min() restricts setting
640d5ac70f0Sopenharmony_ci			 * to >= period size. This conflicts at least with our
641d5ac70f0Sopenharmony_ci			 * dshare patch which allows combining multiple periods
642d5ac70f0Sopenharmony_ci			 * or with slaves which return hw postions between
643d5ac70f0Sopenharmony_ci			 * periods -> set directly in sw_param structure
644d5ac70f0Sopenharmony_ci			 */
645d5ac70f0Sopenharmony_ci			swparams->avail_min = needed_slave_avail_min;
646d5ac70f0Sopenharmony_ci			snd_pcm_sw_params(slave, swparams);
647d5ac70f0Sopenharmony_ci		}
648d5ac70f0Sopenharmony_ci		avail = available;
649d5ac70f0Sopenharmony_ci	}
650d5ac70f0Sopenharmony_ci	return snd_pcm_generic_may_wait_for_avail_min(pcm, avail);
651d5ac70f0Sopenharmony_ci}
652d5ac70f0Sopenharmony_ci
653d5ac70f0Sopenharmony_ciint snd_pcm_plugin_may_wait_for_avail_min(snd_pcm_t *pcm,
654d5ac70f0Sopenharmony_ci					  snd_pcm_uframes_t avail)
655d5ac70f0Sopenharmony_ci{
656d5ac70f0Sopenharmony_ci	return snd_pcm_plugin_may_wait_for_avail_min_conv(pcm, avail, NULL);
657d5ac70f0Sopenharmony_ci}
658d5ac70f0Sopenharmony_ci
659d5ac70f0Sopenharmony_ciconst snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = {
660d5ac70f0Sopenharmony_ci	.status = snd_pcm_plugin_status,
661d5ac70f0Sopenharmony_ci	.state = snd_pcm_generic_state,
662d5ac70f0Sopenharmony_ci	.hwsync = snd_pcm_generic_hwsync,
663d5ac70f0Sopenharmony_ci	.delay = snd_pcm_plugin_delay,
664d5ac70f0Sopenharmony_ci	.prepare = snd_pcm_plugin_prepare,
665d5ac70f0Sopenharmony_ci	.reset = snd_pcm_plugin_reset,
666d5ac70f0Sopenharmony_ci	.start = snd_pcm_generic_start,
667d5ac70f0Sopenharmony_ci	.drop = snd_pcm_generic_drop,
668d5ac70f0Sopenharmony_ci	.drain = snd_pcm_generic_drain,
669d5ac70f0Sopenharmony_ci	.pause = snd_pcm_generic_pause,
670d5ac70f0Sopenharmony_ci	.rewindable = snd_pcm_plugin_rewindable,
671d5ac70f0Sopenharmony_ci	.rewind = snd_pcm_plugin_rewind,
672d5ac70f0Sopenharmony_ci	.forwardable = snd_pcm_plugin_forwardable,
673d5ac70f0Sopenharmony_ci	.forward = snd_pcm_plugin_forward,
674d5ac70f0Sopenharmony_ci	.resume = snd_pcm_generic_resume,
675d5ac70f0Sopenharmony_ci	.link = snd_pcm_generic_link,
676d5ac70f0Sopenharmony_ci	.link_slaves = snd_pcm_generic_link_slaves,
677d5ac70f0Sopenharmony_ci	.unlink = snd_pcm_generic_unlink,
678d5ac70f0Sopenharmony_ci	.writei = snd_pcm_plugin_writei,
679d5ac70f0Sopenharmony_ci	.writen = snd_pcm_plugin_writen,
680d5ac70f0Sopenharmony_ci	.readi = snd_pcm_plugin_readi,
681d5ac70f0Sopenharmony_ci	.readn = snd_pcm_plugin_readn,
682d5ac70f0Sopenharmony_ci	.avail_update = snd_pcm_plugin_avail_update,
683d5ac70f0Sopenharmony_ci	.mmap_commit = snd_pcm_plugin_mmap_commit,
684d5ac70f0Sopenharmony_ci	.htimestamp = snd_pcm_generic_htimestamp,
685d5ac70f0Sopenharmony_ci	.poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
686d5ac70f0Sopenharmony_ci	.poll_descriptors = snd_pcm_generic_poll_descriptors,
687d5ac70f0Sopenharmony_ci	.poll_revents = snd_pcm_generic_poll_revents,
688d5ac70f0Sopenharmony_ci	.may_wait_for_avail_min = snd_pcm_plugin_may_wait_for_avail_min,
689d5ac70f0Sopenharmony_ci};
690d5ac70f0Sopenharmony_ci
691d5ac70f0Sopenharmony_ci#endif
692