Blame src/pcm/pcm_ioplug.c

Packit Service db8eaa
/**
Packit Service db8eaa
 * \file pcm/pcm_ioplug.c
Packit Service db8eaa
 * \ingroup Plugin_SDK
Packit Service db8eaa
 * \brief I/O Plugin SDK
Packit Service db8eaa
 * \author Takashi Iwai <tiwai@suse.de>
Packit Service db8eaa
 * \date 2005
Packit Service db8eaa
 */
Packit Service db8eaa
/*
Packit Service db8eaa
 *  PCM - External I/O Plugin SDK
Packit Service db8eaa
 *  Copyright (c) 2005 by Takashi Iwai <tiwai@suse.de>
Packit Service db8eaa
 *
Packit Service db8eaa
 *
Packit Service db8eaa
 *   This library is free software; you can redistribute it and/or modify
Packit Service db8eaa
 *   it under the terms of the GNU Lesser General Public License as
Packit Service db8eaa
 *   published by the Free Software Foundation; either version 2.1 of
Packit Service db8eaa
 *   the License, or (at your option) any later version.
Packit Service db8eaa
 *
Packit Service db8eaa
 *   This program is distributed in the hope that it will be useful,
Packit Service db8eaa
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service db8eaa
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service db8eaa
 *   GNU Lesser General Public License for more details.
Packit Service db8eaa
 *
Packit Service db8eaa
 *   You should have received a copy of the GNU Lesser General Public
Packit Service db8eaa
 *   License along with this library; if not, write to the Free Software
Packit Service db8eaa
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit Service db8eaa
 *
Packit Service db8eaa
 */
Packit Service db8eaa
  
Packit Service db8eaa
#include "pcm_local.h"
Packit Service db8eaa
#include "pcm_ioplug.h"
Packit Service db8eaa
#include "pcm_ext_parm.h"
Packit Service db8eaa
#include "pcm_generic.h"
Packit Service db8eaa
Packit Service db8eaa
#ifndef PIC
Packit Service db8eaa
/* entry for static linking */
Packit Service db8eaa
const char *_snd_module_pcm_ioplug = "";
Packit Service db8eaa
#endif
Packit Service db8eaa
Packit Service db8eaa
#ifndef DOC_HIDDEN
Packit Service db8eaa
Packit Service db8eaa
/* hw_params */
Packit Service db8eaa
typedef struct snd_pcm_ioplug_priv {
Packit Service db8eaa
	snd_pcm_ioplug_t *data;
Packit Service db8eaa
	struct snd_ext_parm params[SND_PCM_IOPLUG_HW_PARAMS];
Packit Service db8eaa
	snd_pcm_uframes_t last_hw;
Packit Service db8eaa
	snd_pcm_uframes_t avail_max;
Packit Service db8eaa
	snd_htimestamp_t trigger_tstamp;
Packit Service db8eaa
} ioplug_priv_t;
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_drop(snd_pcm_t *pcm);
Packit Service db8eaa
static int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm);
Packit Service db8eaa
static int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space);
Packit Service db8eaa
static int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
Packit Service db8eaa
Packit Service db8eaa
/* update the hw pointer */
Packit Service db8eaa
/* called in lock */
Packit Service db8eaa
static void snd_pcm_ioplug_hw_ptr_update(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
	snd_pcm_sframes_t hw;
Packit Service db8eaa
Packit Service db8eaa
	hw = io->data->callback->pointer(io->data);
Packit Service db8eaa
	if (hw >= 0) {
Packit Service db8eaa
		snd_pcm_uframes_t delta;
Packit Service db8eaa
		snd_pcm_uframes_t avail;
Packit Service db8eaa
Packit Service db8eaa
		if ((snd_pcm_uframes_t)hw >= io->last_hw)
Packit Service db8eaa
			delta = hw - io->last_hw;
Packit Service db8eaa
		else {
Packit Service db8eaa
			const snd_pcm_uframes_t wrap_point =
Packit Service db8eaa
				(io->data->flags & SND_PCM_IOPLUG_FLAG_BOUNDARY_WA) ?
Packit Service db8eaa
					pcm->boundary : pcm->buffer_size;
Packit Service db8eaa
			delta = wrap_point + hw - io->last_hw;
Packit Service db8eaa
		}
Packit Service db8eaa
		snd_pcm_mmap_hw_forward(io->data->pcm, delta);
Packit Service db8eaa
		/* stop the stream if all samples are drained */
Packit Service db8eaa
		if (io->data->state == SND_PCM_STATE_DRAINING) {
Packit Service db8eaa
			avail = snd_pcm_mmap_avail(pcm);
Packit Service db8eaa
			if (avail >= pcm->buffer_size)
Packit Service db8eaa
				snd_pcm_ioplug_drop(pcm);
Packit Service db8eaa
		}
Packit Service db8eaa
		io->last_hw = (snd_pcm_uframes_t)hw;
Packit Service db8eaa
	} else {
Packit Service db8eaa
		if (io->data->state == SND_PCM_STATE_DRAINING)
Packit Service db8eaa
			snd_pcm_ioplug_drop(pcm);
Packit Service db8eaa
		else
Packit Service db8eaa
			io->data->state = SNDRV_PCM_STATE_XRUN;
Packit Service db8eaa
	}
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
Packit Service db8eaa
{
Packit Service db8eaa
	memset(info, 0, sizeof(*info));
Packit Service db8eaa
	info->stream = pcm->stream;
Packit Service db8eaa
	info->card = -1;
Packit Service db8eaa
	if (pcm->name) {
Packit Service db8eaa
		snd_strlcpy((char *)info->id, pcm->name, sizeof(info->id));
Packit Service db8eaa
		snd_strlcpy((char *)info->name, pcm->name, sizeof(info->name));
Packit Service db8eaa
		snd_strlcpy((char *)info->subname, pcm->name, sizeof(info->subname));
Packit Service db8eaa
	}
Packit Service db8eaa
	info->subdevices_count = 1;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
Packit Service db8eaa
{
Packit Service db8eaa
	return snd_pcm_channel_info_shm(pcm, info, -1);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
Packit Service db8eaa
	memset(status, 0, sizeof(*status));
Packit Service db8eaa
	snd_pcm_ioplug_hw_ptr_update(pcm);
Packit Service db8eaa
	status->state = io->data->state;
Packit Service db8eaa
	status->trigger_tstamp = io->trigger_tstamp;
Packit Service db8eaa
	status->avail = snd_pcm_mmap_avail(pcm);
Packit Service db8eaa
	status->avail_max = io->avail_max;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_state_t snd_pcm_ioplug_state(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
	return io->data->state;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_hwsync(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_ioplug_hw_ptr_update(pcm);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
Packit Service db8eaa
	if (io->data->version >= 0x010001 &&
Packit Service db8eaa
	    io->data->callback->delay)
Packit Service db8eaa
		return io->data->callback->delay(io->data, delayp);
Packit Service db8eaa
	else {
Packit Service db8eaa
		snd_pcm_ioplug_hw_ptr_update(pcm);
Packit Service db8eaa
		*delayp = snd_pcm_mmap_hw_avail(pcm);
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_reset(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
Packit Service db8eaa
	io->data->appl_ptr = 0;
Packit Service db8eaa
	io->data->hw_ptr = 0;
Packit Service db8eaa
	io->last_hw = 0;
Packit Service db8eaa
	io->avail_max = 0;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_prepare(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
	int err = 0;
Packit Service db8eaa
Packit Service db8eaa
	snd_pcm_ioplug_reset(pcm);
Packit Service db8eaa
	if (io->data->callback->prepare) {
Packit Service db8eaa
		snd_pcm_unlock(pcm); /* to avoid deadlock */
Packit Service db8eaa
		err = io->data->callback->prepare(io->data);
Packit Service db8eaa
		snd_pcm_lock(pcm);
Packit Service db8eaa
	}
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
Packit Service db8eaa
	io->data->state = SND_PCM_STATE_PREPARED;
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static const int hw_params_type[SND_PCM_IOPLUG_HW_PARAMS] = {
Packit Service db8eaa
	[SND_PCM_IOPLUG_HW_ACCESS] = SND_PCM_HW_PARAM_ACCESS,
Packit Service db8eaa
	[SND_PCM_IOPLUG_HW_FORMAT] = SND_PCM_HW_PARAM_FORMAT,
Packit Service db8eaa
	[SND_PCM_IOPLUG_HW_CHANNELS] = SND_PCM_HW_PARAM_CHANNELS,
Packit Service db8eaa
	[SND_PCM_IOPLUG_HW_RATE] = SND_PCM_HW_PARAM_RATE,
Packit Service db8eaa
	[SND_PCM_IOPLUG_HW_PERIOD_BYTES] = SND_PCM_HW_PARAM_PERIOD_BYTES,
Packit Service db8eaa
	[SND_PCM_IOPLUG_HW_BUFFER_BYTES] = SND_PCM_HW_PARAM_BUFFER_BYTES,
Packit Service db8eaa
	[SND_PCM_IOPLUG_HW_PERIODS] = SND_PCM_HW_PARAM_PERIODS,
Packit Service db8eaa
};
Packit Service db8eaa
Packit Service db8eaa
/* x = a * b */
Packit Service db8eaa
static int rule_mul(snd_pcm_hw_params_t *params, int x, int a, int b)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_interval_t t;
Packit Service db8eaa
Packit Service db8eaa
	snd_interval_mul(hw_param_interval(params, a),
Packit Service db8eaa
			 hw_param_interval(params, b), &t);
Packit Service db8eaa
	return snd_interval_refine(hw_param_interval(params, x), &t);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* x = a / b */
Packit Service db8eaa
static int rule_div(snd_pcm_hw_params_t *params, int x, int a, int b)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_interval_t t;
Packit Service db8eaa
Packit Service db8eaa
	snd_interval_div(hw_param_interval(params, a),
Packit Service db8eaa
			 hw_param_interval(params, b), &t);
Packit Service db8eaa
	return snd_interval_refine(hw_param_interval(params, x), &t);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* x = a * b / k */
Packit Service db8eaa
static int rule_muldivk(snd_pcm_hw_params_t *params, int x, int a, int b, int k)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_interval_t t;
Packit Service db8eaa
Packit Service db8eaa
	snd_interval_muldivk(hw_param_interval(params, a),
Packit Service db8eaa
			     hw_param_interval(params, b), k, &t);
Packit Service db8eaa
	return snd_interval_refine(hw_param_interval(params, x), &t);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* x = a * k / b */
Packit Service db8eaa
static int rule_mulkdiv(snd_pcm_hw_params_t *params, int x, int a, int k, int b)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_interval_t t;
Packit Service db8eaa
Packit Service db8eaa
	snd_interval_mulkdiv(hw_param_interval(params, a), k,
Packit Service db8eaa
			     hw_param_interval(params, b), &t);
Packit Service db8eaa
	return snd_interval_refine(hw_param_interval(params, x), &t);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
#if 0
Packit Service db8eaa
static void dump_parm(snd_pcm_hw_params_t *params)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_output_t *log;
Packit Service db8eaa
	snd_output_stdio_attach(&log, stderr, 0);
Packit Service db8eaa
	snd_pcm_hw_params_dump(params, log);
Packit Service db8eaa
	snd_output_close(log);
Packit Service db8eaa
}
Packit Service db8eaa
#endif
Packit Service db8eaa
Packit Service db8eaa
/* refine *_TIME and *_SIZE, then update *_BYTES */
Packit Service db8eaa
static int refine_time_and_size(snd_pcm_hw_params_t *params,
Packit Service db8eaa
				int time, int size, int bytes)
Packit Service db8eaa
{
Packit Service db8eaa
	int err, change1 = 0;
Packit Service db8eaa
Packit Service db8eaa
	/* size = time * rate / 1000000 */
Packit Service db8eaa
	err = rule_muldivk(params, size, time,
Packit Service db8eaa
			   SND_PCM_HW_PARAM_RATE, 1000000);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	change1 |= err;
Packit Service db8eaa
Packit Service db8eaa
	/* bytes = size * framebits / 8 */
Packit Service db8eaa
	err = rule_muldivk(params, bytes, size,
Packit Service db8eaa
			   SND_PCM_HW_PARAM_FRAME_BITS, 8);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	change1 |= err;
Packit Service db8eaa
	return change1;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* refine *_TIME and *_SIZE from *_BYTES */
Packit Service db8eaa
static int refine_back_time_and_size(snd_pcm_hw_params_t *params,
Packit Service db8eaa
				     int time, int size, int bytes)
Packit Service db8eaa
{
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	/* size = bytes * 8 / framebits */
Packit Service db8eaa
	err = rule_mulkdiv(params, size, bytes, 8, SND_PCM_HW_PARAM_FRAME_BITS);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	/* time = size * 1000000 / rate */
Packit Service db8eaa
	err = rule_mulkdiv(params, time, size, 1000000, SND_PCM_HW_PARAM_RATE);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit Service db8eaa
{
Packit Service db8eaa
	int change = 0, change1, change2, err;
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
	struct snd_ext_parm *p;
Packit Service db8eaa
	unsigned int i;
Packit Service db8eaa
Packit Service db8eaa
	/* access, format */
Packit Service db8eaa
	for (i = SND_PCM_IOPLUG_HW_ACCESS; i <= SND_PCM_IOPLUG_HW_FORMAT; i++) {
Packit Service db8eaa
		err = snd_ext_parm_mask_refine(hw_param_mask(params, hw_params_type[i]),
Packit Service db8eaa
					       io->params, i);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		change |= err;
Packit Service db8eaa
	}
Packit Service db8eaa
	/* channels, rate */
Packit Service db8eaa
	for (; i <= SND_PCM_IOPLUG_HW_RATE; i++) {
Packit Service db8eaa
		err = snd_ext_parm_interval_refine(hw_param_interval(params, hw_params_type[i]),
Packit Service db8eaa
						   io->params, i);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		change |= err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (params->rmask & ((1 << SND_PCM_HW_PARAM_ACCESS) |
Packit Service db8eaa
			     (1 << SND_PCM_HW_PARAM_FORMAT) |
Packit Service db8eaa
			     (1 << SND_PCM_HW_PARAM_SUBFORMAT) |
Packit Service db8eaa
			     (1 << SND_PCM_HW_PARAM_CHANNELS) |
Packit Service db8eaa
			     (1 << SND_PCM_HW_PARAM_RATE))) {
Packit Service db8eaa
		err = snd_pcm_hw_refine_soft(pcm, params);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		change |= err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
Packit Service db8eaa
				       SND_PCM_HW_PARAM_PERIOD_SIZE,
Packit Service db8eaa
				       SND_PCM_HW_PARAM_PERIOD_BYTES);
Packit Service db8eaa
	if (change1 < 0)
Packit Service db8eaa
		return change1;
Packit Service db8eaa
	err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES),
Packit Service db8eaa
					   io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	change1 |= err;
Packit Service db8eaa
	if (change1) {
Packit Service db8eaa
		change |= change1;
Packit Service db8eaa
		err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
Packit Service db8eaa
						SND_PCM_HW_PARAM_PERIOD_SIZE,
Packit Service db8eaa
						SND_PCM_HW_PARAM_PERIOD_BYTES);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME,
Packit Service db8eaa
				       SND_PCM_HW_PARAM_BUFFER_SIZE,
Packit Service db8eaa
				       SND_PCM_HW_PARAM_BUFFER_BYTES);
Packit Service db8eaa
	if (change1 < 0)
Packit Service db8eaa
		return change1;
Packit Service db8eaa
	change |= change1;
Packit Service db8eaa
Packit Service db8eaa
	do {
Packit Service db8eaa
		change2 = 0;
Packit Service db8eaa
		err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_BUFFER_BYTES),
Packit Service db8eaa
						   io->params, SND_PCM_IOPLUG_HW_BUFFER_BYTES);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		change2 |= err;
Packit Service db8eaa
		/* periods = buffer_bytes / period_bytes */
Packit Service db8eaa
		err = rule_div(params, SND_PCM_HW_PARAM_PERIODS,
Packit Service db8eaa
			       SND_PCM_HW_PARAM_BUFFER_BYTES,
Packit Service db8eaa
			       SND_PCM_HW_PARAM_PERIOD_BYTES);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		change2 |= err;
Packit Service db8eaa
		err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIODS),
Packit Service db8eaa
						   io->params, SND_PCM_IOPLUG_HW_PERIODS);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		change2 |= err;
Packit Service db8eaa
		/* buffer_bytes = periods * period_bytes */
Packit Service db8eaa
		err = rule_mul(params, SND_PCM_HW_PARAM_BUFFER_BYTES,
Packit Service db8eaa
			       SND_PCM_HW_PARAM_PERIOD_BYTES,
Packit Service db8eaa
			       SND_PCM_HW_PARAM_PERIODS);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		change2 |= err;
Packit Service db8eaa
		change1 |= change2;
Packit Service db8eaa
	} while (change2);
Packit Service db8eaa
	change |= change1;
Packit Service db8eaa
Packit Service db8eaa
	if (change1) {
Packit Service db8eaa
		err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME,
Packit Service db8eaa
						SND_PCM_HW_PARAM_BUFFER_SIZE,
Packit Service db8eaa
						SND_PCM_HW_PARAM_BUFFER_BYTES);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	/* period_bytes = buffer_bytes / periods */
Packit Service db8eaa
	err = rule_div(params, SND_PCM_HW_PARAM_PERIOD_BYTES,
Packit Service db8eaa
		       SND_PCM_HW_PARAM_BUFFER_BYTES,
Packit Service db8eaa
		       SND_PCM_HW_PARAM_PERIODS);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	if (err) {
Packit Service db8eaa
		/* update period_size and period_time */
Packit Service db8eaa
		change |= err;
Packit Service db8eaa
		err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES),
Packit Service db8eaa
						   io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
Packit Service db8eaa
						SND_PCM_HW_PARAM_PERIOD_SIZE,
Packit Service db8eaa
						SND_PCM_HW_PARAM_PERIOD_BYTES);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	params->info = SND_PCM_INFO_BLOCK_TRANSFER;
Packit Service db8eaa
	p = &io->params[SND_PCM_IOPLUG_HW_ACCESS];
Packit Service db8eaa
	if (p->active) {
Packit Service db8eaa
		for (i = 0; i < p->num_list; i++)
Packit Service db8eaa
			switch (p->list[i]) {
Packit Service db8eaa
			case SND_PCM_ACCESS_MMAP_INTERLEAVED:
Packit Service db8eaa
			case SND_PCM_ACCESS_RW_INTERLEAVED:
Packit Service db8eaa
				params->info |= SND_PCM_INFO_INTERLEAVED;
Packit Service db8eaa
				break;
Packit Service db8eaa
			case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
Packit Service db8eaa
			case SND_PCM_ACCESS_RW_NONINTERLEAVED:
Packit Service db8eaa
				params->info |= SND_PCM_INFO_NONINTERLEAVED;
Packit Service db8eaa
				break;
Packit Service db8eaa
			}
Packit Service db8eaa
	}
Packit Service db8eaa
	if (io->data->callback->pause)
Packit Service db8eaa
		params->info |= SND_PCM_INFO_PAUSE;
Packit Service db8eaa
	if (io->data->callback->resume)
Packit Service db8eaa
		params->info |= SND_PCM_INFO_RESUME;
Packit Service db8eaa
Packit Service db8eaa
#if 0
Packit Service db8eaa
	fprintf(stderr, "XXX\n");
Packit Service db8eaa
	dump_parm(params);
Packit Service db8eaa
#endif
Packit Service db8eaa
	return change;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access);
Packit Service db8eaa
	INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format);
Packit Service db8eaa
	INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels);
Packit Service db8eaa
	INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0);
Packit Service db8eaa
	INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0);
Packit Service db8eaa
	INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size);
Packit Service db8eaa
	if (io->data->callback->hw_params) {
Packit Service db8eaa
		err = io->data->callback->hw_params(io->data, params);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access);
Packit Service db8eaa
		INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format);
Packit Service db8eaa
		INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels);
Packit Service db8eaa
		INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0);
Packit Service db8eaa
		INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0);
Packit Service db8eaa
		INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size);
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_hw_free(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
Packit Service db8eaa
	if (io->data->callback->hw_free)
Packit Service db8eaa
		return io->data->callback->hw_free(io->data);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (!io->data->callback->sw_params)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	snd_pcm_unlock(pcm); /* to avoid deadlock */
Packit Service db8eaa
	err = io->data->callback->sw_params(io->data, params);
Packit Service db8eaa
	snd_pcm_lock(pcm);
Packit Service db8eaa
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_start(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
	int err;
Packit Service db8eaa
	
Packit Service db8eaa
	if (io->data->state != SND_PCM_STATE_PREPARED)
Packit Service db8eaa
		return -EBADFD;
Packit Service db8eaa
Packit Service db8eaa
	err = io->data->callback->start(io->data);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
Packit Service db8eaa
	gettimestamp(&io->trigger_tstamp, pcm->tstamp_type);
Packit Service db8eaa
	io->data->state = SND_PCM_STATE_RUNNING;
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_drop(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
Packit Service db8eaa
	if (io->data->state == SND_PCM_STATE_OPEN)
Packit Service db8eaa
		return -EBADFD;
Packit Service db8eaa
Packit Service db8eaa
	io->data->callback->stop(io->data);
Packit Service db8eaa
Packit Service db8eaa
	gettimestamp(&io->trigger_tstamp, pcm->tstamp_type);
Packit Service db8eaa
	io->data->state = SND_PCM_STATE_SETUP;
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int ioplug_drain_via_poll(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
Packit Service db8eaa
	while (io->data->state == SND_PCM_STATE_DRAINING) {
Packit Service db8eaa
		snd_pcm_ioplug_hw_ptr_update(pcm);
Packit Service db8eaa
		if (io->data->state != SND_PCM_STATE_DRAINING)
Packit Service db8eaa
			break;
Packit Service db8eaa
		/* in non-blocking mode, let application to poll() by itself */
Packit Service db8eaa
		if (io->data->nonblock)
Packit Service db8eaa
			return -EAGAIN;
Packit Service db8eaa
		if (snd_pcm_wait_nocheck(pcm, -1) < 0)
Packit Service db8eaa
			break;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0; /* force to drop at error */
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* need own locking */
Packit Service db8eaa
static int snd_pcm_ioplug_drain(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
	int err = 0;
Packit Service db8eaa
Packit Service db8eaa
	snd_pcm_lock(pcm);
Packit Service db8eaa
	switch (io->data->state) {
Packit Service db8eaa
	case SND_PCM_STATE_OPEN:
Packit Service db8eaa
	case SND_PCM_STATE_DISCONNECTED:
Packit Service db8eaa
	case SND_PCM_STATE_SUSPENDED:
Packit Service db8eaa
		snd_pcm_unlock(pcm);
Packit Service db8eaa
		return -EBADFD;
Packit Service db8eaa
	case SND_PCM_STATE_PREPARED:
Packit Service db8eaa
		if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
Packit Service db8eaa
			if (!io->data->callback->drain) {
Packit Service db8eaa
				err = snd_pcm_ioplug_start(pcm);
Packit Service db8eaa
				if (err < 0)
Packit Service db8eaa
					goto unlock;
Packit Service db8eaa
			}
Packit Service db8eaa
			io->data->state = SND_PCM_STATE_DRAINING;
Packit Service db8eaa
		}
Packit Service db8eaa
		break;
Packit Service db8eaa
	case SND_PCM_STATE_RUNNING:
Packit Service db8eaa
		io->data->state = SND_PCM_STATE_DRAINING;
Packit Service db8eaa
		break;
Packit Service db8eaa
	default:
Packit Service db8eaa
		break;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (io->data->state == SND_PCM_STATE_DRAINING) {
Packit Service db8eaa
		if (io->data->callback->drain) {
Packit Service db8eaa
			snd_pcm_unlock(pcm); /* let plugin own locking */
Packit Service db8eaa
			err = io->data->callback->drain(io->data);
Packit Service db8eaa
			snd_pcm_lock(pcm);
Packit Service db8eaa
		} else {
Packit Service db8eaa
			err = ioplug_drain_via_poll(pcm);
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
 unlock:
Packit Service db8eaa
	if (!err && io->data->state != SND_PCM_STATE_SETUP)
Packit Service db8eaa
		snd_pcm_ioplug_drop(pcm);
Packit Service db8eaa
	snd_pcm_unlock(pcm);
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_pause(snd_pcm_t *pcm, int enable)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
	static const snd_pcm_state_t states[2] = {
Packit Service db8eaa
		SND_PCM_STATE_RUNNING, SND_PCM_STATE_PAUSED
Packit Service db8eaa
	};
Packit Service db8eaa
	int prev, err;
Packit Service db8eaa
Packit Service db8eaa
	prev = !enable;
Packit Service db8eaa
	enable = !prev;
Packit Service db8eaa
	if (io->data->state != states[prev])
Packit Service db8eaa
		return -EBADFD;
Packit Service db8eaa
	if (io->data->callback->pause) {
Packit Service db8eaa
		err = io->data->callback->pause(io->data, enable);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	io->data->state = states[enable];
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_ioplug_rewindable(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	return snd_pcm_mmap_hw_rewindable(pcm);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_ioplug_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_mmap_appl_backward(pcm, frames);
Packit Service db8eaa
	return frames;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_ioplug_forwardable(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	return snd_pcm_mmap_avail(pcm);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_ioplug_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_mmap_appl_forward(pcm, frames);
Packit Service db8eaa
	return frames;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* need own locking */
Packit Service db8eaa
static int snd_pcm_ioplug_resume(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
Packit Service db8eaa
	if (io->data->callback->resume)
Packit Service db8eaa
		io->data->callback->resume(io->data);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* called in lock */
Packit Service db8eaa
static snd_pcm_sframes_t ioplug_priv_transfer_areas(snd_pcm_t *pcm,
Packit Service db8eaa
						       const snd_pcm_channel_area_t *areas,
Packit Service db8eaa
						       snd_pcm_uframes_t offset,
Packit Service db8eaa
						       snd_pcm_uframes_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
	snd_pcm_sframes_t result;
Packit Service db8eaa
		
Packit Service db8eaa
	if (! size)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
	if (io->data->callback->transfer)
Packit Service db8eaa
		result = io->data->callback->transfer(io->data, areas, offset, size);
Packit Service db8eaa
	else
Packit Service db8eaa
		result = size;
Packit Service db8eaa
	if (result > 0)
Packit Service db8eaa
		snd_pcm_mmap_appl_forward(pcm, result);
Packit Service db8eaa
	return result;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_ioplug_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	if (pcm->mmap_rw)
Packit Service db8eaa
		return snd_pcm_mmap_writei(pcm, buffer, size);
Packit Service db8eaa
	else {
Packit Service db8eaa
		snd_pcm_channel_area_t areas[pcm->channels];
Packit Service db8eaa
		snd_pcm_areas_from_buf(pcm, areas, (void*)buffer);
Packit Service db8eaa
		return snd_pcm_write_areas(pcm, areas, 0, size, 
Packit Service db8eaa
					   ioplug_priv_transfer_areas);
Packit Service db8eaa
	}
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_ioplug_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	if (pcm->mmap_rw)
Packit Service db8eaa
		return snd_pcm_mmap_writen(pcm, bufs, size);
Packit Service db8eaa
	else {
Packit Service db8eaa
		snd_pcm_channel_area_t areas[pcm->channels];
Packit Service db8eaa
		snd_pcm_areas_from_bufs(pcm, areas, bufs);
Packit Service db8eaa
		return snd_pcm_write_areas(pcm, areas, 0, size,
Packit Service db8eaa
					   ioplug_priv_transfer_areas);
Packit Service db8eaa
	}
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_ioplug_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	if (pcm->mmap_rw)
Packit Service db8eaa
		return snd_pcm_mmap_readi(pcm, buffer, size);
Packit Service db8eaa
	else {
Packit Service db8eaa
		snd_pcm_channel_area_t areas[pcm->channels];
Packit Service db8eaa
		snd_pcm_areas_from_buf(pcm, areas, buffer);
Packit Service db8eaa
		return snd_pcm_read_areas(pcm, areas, 0, size,
Packit Service db8eaa
					  ioplug_priv_transfer_areas);
Packit Service db8eaa
	}
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_ioplug_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	if (pcm->mmap_rw)
Packit Service db8eaa
		return snd_pcm_mmap_readn(pcm, bufs, size);
Packit Service db8eaa
	else {
Packit Service db8eaa
		snd_pcm_channel_area_t areas[pcm->channels];
Packit Service db8eaa
		snd_pcm_areas_from_bufs(pcm, areas, bufs);
Packit Service db8eaa
		return snd_pcm_read_areas(pcm, areas, 0, size,
Packit Service db8eaa
					  ioplug_priv_transfer_areas);
Packit Service db8eaa
	}
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_ioplug_mmap_commit(snd_pcm_t *pcm,
Packit Service db8eaa
						    snd_pcm_uframes_t offset,
Packit Service db8eaa
						    snd_pcm_uframes_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
Packit Service db8eaa
	    pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
Packit Service db8eaa
	    pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) {
Packit Service db8eaa
		const snd_pcm_channel_area_t *areas;
Packit Service db8eaa
		snd_pcm_uframes_t ofs, frames = size;
Packit Service db8eaa
Packit Service db8eaa
		__snd_pcm_mmap_begin(pcm, &areas, &ofs, &frames);
Packit Service db8eaa
		if (ofs != offset)
Packit Service db8eaa
			return -EIO;
Packit Service db8eaa
		return ioplug_priv_transfer_areas(pcm, areas, offset, frames);
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	snd_pcm_mmap_appl_forward(pcm, size);
Packit Service db8eaa
	return size;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_sframes_t snd_pcm_ioplug_avail_update(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
	snd_pcm_uframes_t avail;
Packit Service db8eaa
Packit Service db8eaa
	snd_pcm_ioplug_hw_ptr_update(pcm);
Packit Service db8eaa
	if (io->data->state == SND_PCM_STATE_XRUN)
Packit Service db8eaa
		return -EPIPE;
Packit Service db8eaa
Packit Service db8eaa
	avail = snd_pcm_mmap_avail(pcm);
Packit Service db8eaa
	if (pcm->stream == SND_PCM_STREAM_CAPTURE &&
Packit Service db8eaa
	    pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
Packit Service db8eaa
	    pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) {
Packit Service db8eaa
		if (io->data->callback->transfer) {
Packit Service db8eaa
			const snd_pcm_channel_area_t *areas;
Packit Service db8eaa
			snd_pcm_uframes_t offset, size = UINT_MAX;
Packit Service db8eaa
			snd_pcm_sframes_t result;
Packit Service db8eaa
Packit Service db8eaa
			__snd_pcm_mmap_begin(pcm, &areas, &offset, &size);
Packit Service db8eaa
			result = io->data->callback->transfer(io->data, areas, offset, size);
Packit Service db8eaa
			if (result < 0)
Packit Service db8eaa
				return result;
Packit Service db8eaa
Packit Service db8eaa
			/* If the available data doesn't fit in the
Packit Service db8eaa
			   contiguous area at the end of the mmap we
Packit Service db8eaa
			   must transfer the remaining data to the
Packit Service db8eaa
			   beginning of the mmap. */
Packit Service db8eaa
			if (size < avail) {
Packit Service db8eaa
				result = io->data->callback->transfer(io->data, areas,
Packit Service db8eaa
								      0, avail - size);
Packit Service db8eaa
				if (result < 0)
Packit Service db8eaa
					return result;
Packit Service db8eaa
			}
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
	if (avail > io->avail_max)
Packit Service db8eaa
		io->avail_max = avail;
Packit Service db8eaa
	return (snd_pcm_sframes_t)avail;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_nonblock(snd_pcm_t *pcm, int nonblock)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
Packit Service db8eaa
	io->data->nonblock = nonblock;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
	int err = 1;
Packit Service db8eaa
Packit Service db8eaa
	if (io->data->callback->poll_descriptors_count) {
Packit Service db8eaa
		snd_pcm_unlock(pcm); /* to avoid deadlock */
Packit Service db8eaa
		err = io->data->callback->poll_descriptors_count(io->data);
Packit Service db8eaa
		snd_pcm_lock(pcm);
Packit Service db8eaa
	}
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (io->data->callback->poll_descriptors) {
Packit Service db8eaa
		snd_pcm_unlock(pcm); /* to avoid deadlock */
Packit Service db8eaa
		err = io->data->callback->poll_descriptors(io->data, pfds, space);
Packit Service db8eaa
		snd_pcm_lock(pcm);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (pcm->poll_fd < 0)
Packit Service db8eaa
		return -EIO;
Packit Service db8eaa
	if (space >= 1 && pfds) {
Packit Service db8eaa
		pfds->fd = pcm->poll_fd;
Packit Service db8eaa
		pfds->events = pcm->poll_events | POLLERR | POLLNVAL;
Packit Service db8eaa
	} else {
Packit Service db8eaa
		return 0;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 1;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (io->data->callback->poll_revents) {
Packit Service db8eaa
		snd_pcm_unlock(pcm); /* to avoid deadlock */
Packit Service db8eaa
		err = io->data->callback->poll_revents(io->data, pfds, nfds, revents);
Packit Service db8eaa
		snd_pcm_lock(pcm);
Packit Service db8eaa
	} else {
Packit Service db8eaa
		*revents = pfds->revents;
Packit Service db8eaa
		err = 0;
Packit Service db8eaa
	}
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
Packit Service db8eaa
{
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
Packit Service db8eaa
				int sig ATTRIBUTE_UNUSED,
Packit Service db8eaa
				pid_t pid ATTRIBUTE_UNUSED)
Packit Service db8eaa
{
Packit Service db8eaa
	return -ENOSYS;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
Packit Service db8eaa
{
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_chmap_query_t **snd_pcm_ioplug_query_chmaps(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
Packit Service db8eaa
	if (io->data->version >= 0x010002 &&
Packit Service db8eaa
	    io->data->callback->query_chmaps)
Packit Service db8eaa
		return io->data->callback->query_chmaps(io->data);
Packit Service db8eaa
	return NULL;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static snd_pcm_chmap_t *snd_pcm_ioplug_get_chmap(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
Packit Service db8eaa
	if (io->data->version >= 0x010002 &&
Packit Service db8eaa
	    io->data->callback->get_chmap)
Packit Service db8eaa
		return io->data->callback->get_chmap(io->data);
Packit Service db8eaa
	return NULL;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
Packit Service db8eaa
	if (io->data->version >= 0x010002 &&
Packit Service db8eaa
	    io->data->callback->set_chmap)
Packit Service db8eaa
		return io->data->callback->set_chmap(io->data, map);
Packit Service db8eaa
	return -ENXIO;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static void snd_pcm_ioplug_dump(snd_pcm_t *pcm, snd_output_t *out)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
Packit Service db8eaa
	if (io->data->callback->dump)
Packit Service db8eaa
		io->data->callback->dump(io->data, out);
Packit Service db8eaa
	else {
Packit Service db8eaa
		if (io->data->name)
Packit Service db8eaa
			snd_output_printf(out, "%s\n", io->data->name);
Packit Service db8eaa
		else
Packit Service db8eaa
			snd_output_printf(out, "IO-PCM Plugin\n");
Packit Service db8eaa
		if (pcm->setup) {
Packit Service db8eaa
			snd_output_printf(out, "Its setup is:\n");
Packit Service db8eaa
			snd_pcm_dump_setup(pcm, out);
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static void clear_io_params(ioplug_priv_t *io)
Packit Service db8eaa
{
Packit Service db8eaa
	int i;
Packit Service db8eaa
	for (i = 0; i < SND_PCM_IOPLUG_HW_PARAMS; i++)
Packit Service db8eaa
		snd_ext_parm_clear(&io->params[i]);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int snd_pcm_ioplug_close(snd_pcm_t *pcm)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = pcm->private_data;
Packit Service db8eaa
Packit Service db8eaa
	clear_io_params(io);
Packit Service db8eaa
	if (io->data->callback->close)
Packit Service db8eaa
		io->data->callback->close(io->data);
Packit Service db8eaa
	free(io);
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static const snd_pcm_ops_t snd_pcm_ioplug_ops = {
Packit Service db8eaa
	.close = snd_pcm_ioplug_close,
Packit Service db8eaa
	.nonblock = snd_pcm_ioplug_nonblock,
Packit Service db8eaa
	.async = snd_pcm_ioplug_async,
Packit Service db8eaa
	.info = snd_pcm_ioplug_info,
Packit Service db8eaa
	.hw_refine = snd_pcm_ioplug_hw_refine,
Packit Service db8eaa
	.hw_params = snd_pcm_ioplug_hw_params,
Packit Service db8eaa
	.hw_free = snd_pcm_ioplug_hw_free,
Packit Service db8eaa
	.sw_params = snd_pcm_ioplug_sw_params,
Packit Service db8eaa
	.channel_info = snd_pcm_ioplug_channel_info,
Packit Service db8eaa
	.dump = snd_pcm_ioplug_dump,
Packit Service db8eaa
	.mmap = snd_pcm_ioplug_mmap,
Packit Service db8eaa
	.munmap = snd_pcm_ioplug_munmap,
Packit Service db8eaa
	.query_chmaps = snd_pcm_ioplug_query_chmaps,
Packit Service db8eaa
	.get_chmap = snd_pcm_ioplug_get_chmap,
Packit Service db8eaa
	.set_chmap = snd_pcm_ioplug_set_chmap,
Packit Service db8eaa
};
Packit Service db8eaa
Packit Service db8eaa
static const snd_pcm_fast_ops_t snd_pcm_ioplug_fast_ops = {
Packit Service db8eaa
	.status = snd_pcm_ioplug_status,
Packit Service db8eaa
	.prepare = snd_pcm_ioplug_prepare,
Packit Service db8eaa
	.reset = snd_pcm_ioplug_reset,
Packit Service db8eaa
	.start = snd_pcm_ioplug_start,
Packit Service db8eaa
	.drop = snd_pcm_ioplug_drop,
Packit Service db8eaa
	.drain = snd_pcm_ioplug_drain,
Packit Service db8eaa
	.pause = snd_pcm_ioplug_pause,
Packit Service db8eaa
	.state = snd_pcm_ioplug_state,
Packit Service db8eaa
	.hwsync = snd_pcm_ioplug_hwsync,
Packit Service db8eaa
	.delay = snd_pcm_ioplug_delay,
Packit Service db8eaa
	.resume = snd_pcm_ioplug_resume,
Packit Service db8eaa
	.link = NULL,
Packit Service db8eaa
	.link_slaves = NULL,
Packit Service db8eaa
	.unlink = NULL,
Packit Service db8eaa
	.rewindable = snd_pcm_ioplug_rewindable,
Packit Service db8eaa
	.rewind = snd_pcm_ioplug_rewind,
Packit Service db8eaa
	.forwardable = snd_pcm_ioplug_forwardable,
Packit Service db8eaa
	.forward = snd_pcm_ioplug_forward,
Packit Service db8eaa
	.writei = snd_pcm_ioplug_writei,
Packit Service db8eaa
	.writen = snd_pcm_ioplug_writen,
Packit Service db8eaa
	.readi = snd_pcm_ioplug_readi,
Packit Service db8eaa
	.readn = snd_pcm_ioplug_readn,
Packit Service db8eaa
	.avail_update = snd_pcm_ioplug_avail_update,
Packit Service db8eaa
	.mmap_commit = snd_pcm_ioplug_mmap_commit,
Packit Service db8eaa
	.htimestamp = snd_pcm_generic_real_htimestamp,
Packit Service db8eaa
	.poll_descriptors_count = snd_pcm_ioplug_poll_descriptors_count,
Packit Service db8eaa
	.poll_descriptors = snd_pcm_ioplug_poll_descriptors,
Packit Service db8eaa
	.poll_revents = snd_pcm_ioplug_poll_revents,
Packit Service db8eaa
};
Packit Service db8eaa
Packit Service db8eaa
#endif /* !DOC_HIDDEN */
Packit Service db8eaa
Packit Service db8eaa
/*
Packit Service db8eaa
 * Exported functions
Packit Service db8eaa
 */
Packit Service db8eaa
Packit Service db8eaa
/*! \page pcm_external_plugins PCM External Plugin SDK
Packit Service db8eaa
Packit Service db8eaa
\section pcm_ioplug External Plugin: I/O Plugin
Packit Service db8eaa
Packit Service db8eaa
The I/O-type plugin is a PCM plugin to work as the input or output terminal point,
Packit Service db8eaa
i.e. as a user-space PCM driver.
Packit Service db8eaa
Packit Service db8eaa
The new plugin is created via #snd_pcm_ioplug_create() function.
Packit Service db8eaa
The first argument is a pointer of the pluging information.  Some of
Packit Service db8eaa
this struct must be initialized in prior to call
Packit Service db8eaa
#snd_pcm_ioplug_create().  Then the function fills other fields in
Packit Service db8eaa
return.  The rest arguments, name, stream and mode, are usually
Packit Service db8eaa
identical with the values passed from the ALSA plugin constructor.
Packit Service db8eaa
Packit Service db8eaa
The following fields are mandatory: version, name, callback.
Packit Service db8eaa
Otherfields are optional and should be initialized with zero.
Packit Service db8eaa
Packit Service db8eaa
The constant #SND_PCM_IOPLUG_VERSION must be passed to the version
Packit Service db8eaa
field for the version check in alsa-lib.  A non-NULL ASCII string
Packit Service db8eaa
has to be passed to the name field.  The callback field contains the 
Packit Service db8eaa
table of callback functions for this plugin (defined as
Packit Service db8eaa
#snd_pcm_ioplug_callback_t).
Packit Service db8eaa
Packit Service db8eaa
flags field specifies the optional bit-flags.  poll_fd and poll_events
Packit Service db8eaa
specify the poll file descriptor and the corresponding poll events
Packit Service db8eaa
(POLLIN, POLLOUT) for the plugin.  If the plugin requires multiple
Packit Service db8eaa
poll descriptors or poll descriptor(s) dynamically varying, set
Packit Service db8eaa
poll_descriptors and poll_descriptors_count callbacks to the callback
Packit Service db8eaa
table.  Then the poll_fd and poll_events field are ignored.
Packit Service db8eaa
Packit Service db8eaa
mmap_rw specifies whether the plugin behaves in the pseudo mmap mode.
Packit Service db8eaa
When this value is set to 1, the plugin creates always a local buffer
Packit Service db8eaa
and performs read/write calls using this buffer as if it's mmapped.
Packit Service db8eaa
The address of local buffer can be obtained via
Packit Service db8eaa
#snd_pcm_ioplug_mmap_areas() function.
Packit Service db8eaa
When poll_fd, poll_events and mmap_rw fields are changed after
Packit Service db8eaa
#snd_pcm_ioplug_create(), call #snd_pcm_ioplug_reinit_status() to
Packit Service db8eaa
reflect the changes.
Packit Service db8eaa
Packit Service db8eaa
The driver can set an arbitrary value (pointer) to private_data
Packit Service db8eaa
field to refer its own data in the callbacks.
Packit Service db8eaa
Packit Service db8eaa
The rest fields are filled by #snd_pcm_ioplug_create().  The pcm field
Packit Service db8eaa
is the resultant PCM handle.  The others are the current status of the
Packit Service db8eaa
PCM.
Packit Service db8eaa
Packit Service db8eaa
The callback functions in #snd_pcm_ioplug_callback_t define the real
Packit Service db8eaa
behavior of the driver.
Packit Service db8eaa
At least, start, stop and pointer callbacks must be given.  Other
Packit Service db8eaa
callbacks are optional.  The start and stop callbacks are called when
Packit Service db8eaa
the PCM stream is started and stopped, repsectively.  The pointer
Packit Service db8eaa
callback returns the current DMA position, which may be called at any
Packit Service db8eaa
time.
Packit Service db8eaa
Packit Service db8eaa
The transfer callback is called when any data transfer happens.  It
Packit Service db8eaa
receives the area array, offset and the size to transfer.  The area
Packit Service db8eaa
array contains the array of snd_pcm_channel_area_t with the elements
Packit Service db8eaa
of number of channels.
Packit Service db8eaa
Packit Service db8eaa
When the PCM is closed, close callback is called.  If the driver
Packit Service db8eaa
allocates any internal buffers, they should be released in this
Packit Service db8eaa
callback.  The hw_params and hw_free callbacks are called when
Packit Service db8eaa
hw_params are set and reset, respectively.  Note that they may be
Packit Service db8eaa
called multiple times according to the application.  Similarly,
Packit Service db8eaa
sw_params callback is called when sw_params is set or changed.
Packit Service db8eaa
Packit Service db8eaa
The prepare, drain, pause and resume callbacks are called when
Packit Service db8eaa
#snd_pcm_prepare(), #snd_pcm_drain(), #snd_pcm_pause(), and
Packit Service db8eaa
#snd_pcm_resume() are called.  The poll_descriptors_count and
Packit Service db8eaa
poll_descriptors callbacks are used to return the multiple or dynamic
Packit Service db8eaa
poll descriptors as mentioned above.  The poll_revents callback is
Packit Service db8eaa
used to modify poll events.  If the driver needs to mangle the native
Packit Service db8eaa
poll events to proper poll events for PCM, you can do it in this
Packit Service db8eaa
callback.
Packit Service db8eaa
Packit Service db8eaa
Finally, the dump callback is used to print the status of the plugin.
Packit Service db8eaa
Packit Service db8eaa
Note that some callbacks (start, stop, pointer, transfer and pause)
Packit Service db8eaa
may be called inside the internal pthread mutex, and they shouldn't
Packit Service db8eaa
call the PCM functions again unnecessarily from the callback itself;
Packit Service db8eaa
otherwise it may lead to a deadlock.
Packit Service db8eaa
Packit Service db8eaa
The hw_params constraints can be defined via either
Packit Service db8eaa
#snd_pcm_ioplug_set_param_minmax() and #snd_pcm_ioplug_set_param_list()
Packit Service db8eaa
functions after calling #snd_pcm_ioplug_create().
Packit Service db8eaa
The former defines the minimal and maximal acceptable values for the
Packit Service db8eaa
given hw_params parameter (SND_PCM_IOPLUG_HW_XXX).
Packit Service db8eaa
This function can't be used for the format parameter.  The latter
Packit Service db8eaa
function specifies the available parameter values as the list.
Packit Service db8eaa
Packit Service db8eaa
To clear the parameter constraints, call #snd_pcm_ioplug_params_reset() function.
Packit Service db8eaa
Packit Service db8eaa
*/
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Create an ioplug instance
Packit Service db8eaa
 * \param ioplug the ioplug handle
Packit Service db8eaa
 * \param name name of PCM
Packit Service db8eaa
 * \param stream stream direction
Packit Service db8eaa
 * \param mode PCM open mode
Packit Service db8eaa
 * \return 0 if successful, or a negative error code
Packit Service db8eaa
 *
Packit Service db8eaa
 * Creates the ioplug instance.
Packit Service db8eaa
 *
Packit Service db8eaa
 * The callback is the mandatory field of ioplug handle.  At least, start, stop and
Packit Service db8eaa
 * pointer callbacks must be set before calling this function.
Packit Service db8eaa
 *
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_pcm_ioplug_create(snd_pcm_ioplug_t *ioplug, const char *name,
Packit Service db8eaa
			  snd_pcm_stream_t stream, int mode)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io;
Packit Service db8eaa
	int err;
Packit Service db8eaa
	snd_pcm_t *pcm;
Packit Service db8eaa
Packit Service db8eaa
	assert(ioplug && ioplug->callback);
Packit Service db8eaa
	assert(ioplug->callback->start &&
Packit Service db8eaa
	       ioplug->callback->stop &&
Packit Service db8eaa
	       ioplug->callback->pointer);
Packit Service db8eaa
Packit Service db8eaa
	/* We support 1.0.0 to current */
Packit Service db8eaa
	if (ioplug->version < 0x010000 ||
Packit Service db8eaa
	    ioplug->version > SND_PCM_IOPLUG_VERSION) {
Packit Service db8eaa
		SNDERR("ioplug: Plugin version mismatch: 0x%x\n",
Packit Service db8eaa
		       ioplug->version);
Packit Service db8eaa
		return -ENXIO;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	io = calloc(1, sizeof(*io));
Packit Service db8eaa
	if (! io)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	io->data = ioplug;
Packit Service db8eaa
	ioplug->state = SND_PCM_STATE_OPEN;
Packit Service db8eaa
	ioplug->stream = stream;
Packit Service db8eaa
Packit Service db8eaa
	err = snd_pcm_new(&pcm, SND_PCM_TYPE_IOPLUG, name, stream, mode);
Packit Service db8eaa
	if (err < 0) {
Packit Service db8eaa
		free(io);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	ioplug->pcm = pcm;
Packit Service db8eaa
	pcm->ops = &snd_pcm_ioplug_ops;
Packit Service db8eaa
	pcm->fast_ops = &snd_pcm_ioplug_fast_ops;
Packit Service db8eaa
	pcm->private_data = io;
Packit Service db8eaa
Packit Service db8eaa
	snd_pcm_set_hw_ptr(pcm, &ioplug->hw_ptr, -1, 0);
Packit Service db8eaa
	snd_pcm_set_appl_ptr(pcm, &ioplug->appl_ptr, -1, 0);
Packit Service db8eaa
Packit Service db8eaa
	snd_pcm_ioplug_reinit_status(ioplug);
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Delete the ioplug instance
Packit Service db8eaa
 * \param ioplug the ioplug handle
Packit Service db8eaa
 * \return 0 if successful, or a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_pcm_ioplug_delete(snd_pcm_ioplug_t *ioplug)
Packit Service db8eaa
{
Packit Service db8eaa
	return snd_pcm_close(ioplug->pcm);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Reset ioplug parameters
Packit Service db8eaa
 * \param ioplug the ioplug handle
Packit Service db8eaa
 *
Packit Service db8eaa
 * Resets the all parameters for the given ioplug handle.
Packit Service db8eaa
 */
Packit Service db8eaa
void snd_pcm_ioplug_params_reset(snd_pcm_ioplug_t *ioplug)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = ioplug->pcm->private_data;
Packit Service db8eaa
	clear_io_params(io);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Set parameter as the list
Packit Service db8eaa
 * \param ioplug the ioplug handle
Packit Service db8eaa
 * \param type parameter type
Packit Service db8eaa
 * \param num_list number of available values
Packit Service db8eaa
 * \param list the list of available values
Packit Service db8eaa
 * \return 0 if successful, or a negative error code
Packit Service db8eaa
 *
Packit Service db8eaa
 * Sets the parameter as the list.
Packit Service db8eaa
 * The available values of the given parameter type is restricted to the ones of the given list.
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_pcm_ioplug_set_param_list(snd_pcm_ioplug_t *ioplug, int type, unsigned int num_list, const unsigned int *list)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = ioplug->pcm->private_data;
Packit Service db8eaa
	if (type < 0 || type >= SND_PCM_IOPLUG_HW_PARAMS) {
Packit Service db8eaa
		SNDERR("IOPLUG: invalid parameter type %d", type);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (type == SND_PCM_IOPLUG_HW_PERIODS)
Packit Service db8eaa
		io->params[type].integer = 1;
Packit Service db8eaa
	return snd_ext_parm_set_list(&io->params[type], num_list, list);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Set parameter as the min/max values
Packit Service db8eaa
 * \param ioplug the ioplug handle
Packit Service db8eaa
 * \param type parameter type
Packit Service db8eaa
 * \param min the minimum value
Packit Service db8eaa
 * \param max the maximum value
Packit Service db8eaa
 * \return 0 if successful, or a negative error code
Packit Service db8eaa
 *
Packit Service db8eaa
 * Sets the parameter as the min/max values.
Packit Service db8eaa
 * The available values of the given parameter type is restricted between the given
Packit Service db8eaa
 * minimum and maximum values.
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_pcm_ioplug_set_param_minmax(snd_pcm_ioplug_t *ioplug, int type, unsigned int min, unsigned int max)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug_priv_t *io = ioplug->pcm->private_data;
Packit Service db8eaa
	if (type < 0 || type >= SND_PCM_IOPLUG_HW_PARAMS) {
Packit Service db8eaa
		SNDERR("IOPLUG: invalid parameter type %d", type);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (type == SND_PCM_IOPLUG_HW_ACCESS || type == SND_PCM_IOPLUG_HW_FORMAT) {
Packit Service db8eaa
		SNDERR("IOPLUG: invalid parameter type %d", type);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (type == SND_PCM_IOPLUG_HW_PERIODS)
Packit Service db8eaa
		io->params[type].integer = 1;
Packit Service db8eaa
	return snd_ext_parm_set_minmax(&io->params[type], min, max);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Reinitialize the poll and mmap status
Packit Service db8eaa
 * \param ioplug the ioplug handle
Packit Service db8eaa
 * \return 0 if successful, or a negative error code
Packit Service db8eaa
 *
Packit Service db8eaa
 * Reinitializes the poll and the mmap status of the PCM.
Packit Service db8eaa
 * Call this function to propagate the status change in the ioplug instance to
Packit Service db8eaa
 * its PCM internals.
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_pcm_ioplug_reinit_status(snd_pcm_ioplug_t *ioplug)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug->pcm->poll_fd = ioplug->poll_fd;
Packit Service db8eaa
	ioplug->pcm->poll_events = ioplug->poll_events;
Packit Service db8eaa
	if (ioplug->flags & SND_PCM_IOPLUG_FLAG_MONOTONIC)
Packit Service db8eaa
		ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC;
Packit Service db8eaa
	else
Packit Service db8eaa
		ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
Packit Service db8eaa
	ioplug->pcm->mmap_rw = ioplug->mmap_rw;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get mmap area of ioplug
Packit Service db8eaa
 * \param ioplug the ioplug handle
Packit Service db8eaa
 * \return the mmap channel areas if available, or NULL
Packit Service db8eaa
 *
Packit Service db8eaa
 * Returns the mmap channel areas if available.  When mmap_rw field is not set,
Packit Service db8eaa
 * this function always returns NULL.
Packit Service db8eaa
 */
Packit Service db8eaa
const snd_pcm_channel_area_t *snd_pcm_ioplug_mmap_areas(snd_pcm_ioplug_t *ioplug)
Packit Service db8eaa
{
Packit Service db8eaa
	if (ioplug->mmap_rw)
Packit Service db8eaa
		return snd_pcm_mmap_areas(ioplug->pcm);
Packit Service db8eaa
	return NULL;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Change the ioplug PCM status
Packit Service db8eaa
 * \param ioplug the ioplug handle
Packit Service db8eaa
 * \param state the PCM status
Packit Service db8eaa
 * \return zero if successful or a negative error code
Packit Service db8eaa
 *
Packit Service db8eaa
 * Changes the PCM status of the ioplug to the given value.
Packit Service db8eaa
 * This function can be used for external plugins to notify the status
Packit Service db8eaa
 * change, e.g. XRUN.
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_pcm_ioplug_set_state(snd_pcm_ioplug_t *ioplug, snd_pcm_state_t state)
Packit Service db8eaa
{
Packit Service db8eaa
	ioplug->state = state;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get the available frames. This function can be used to calculate the
Packit Service db8eaa
 * the available frames before calling #snd_pcm_avail_update()
Packit Service db8eaa
 * \param ioplug the ioplug handle
Packit Service db8eaa
 * \param hw_ptr hardware pointer in frames
Packit Service db8eaa
 * \param appl_ptr application pointer in frames
Packit Service db8eaa
 * \return available frames for the application
Packit Service db8eaa
 */
Packit Service db8eaa
snd_pcm_uframes_t snd_pcm_ioplug_avail(const snd_pcm_ioplug_t * const ioplug,
Packit Service db8eaa
				       const snd_pcm_uframes_t hw_ptr,
Packit Service db8eaa
				       const snd_pcm_uframes_t appl_ptr)
Packit Service db8eaa
{
Packit Service db8eaa
	return __snd_pcm_avail(ioplug->pcm, hw_ptr, appl_ptr);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get the available frames. This function can be used to calculate the
Packit Service db8eaa
 * the available frames before calling #snd_pcm_avail_update()
Packit Service db8eaa
 * \param ioplug the ioplug handle
Packit Service db8eaa
 * \param hw_ptr hardware pointer in frames
Packit Service db8eaa
 * \param appl_ptr application pointer in frames
Packit Service db8eaa
 * \return available frames for the hardware
Packit Service db8eaa
 */
Packit Service db8eaa
snd_pcm_uframes_t snd_pcm_ioplug_hw_avail(const snd_pcm_ioplug_t * const ioplug,
Packit Service db8eaa
					  const snd_pcm_uframes_t hw_ptr,
Packit Service db8eaa
					  const snd_pcm_uframes_t appl_ptr)
Packit Service db8eaa
{
Packit Service db8eaa
	/* available data/space which can be transferred by the user
Packit Service db8eaa
	 * application
Packit Service db8eaa
	 */
Packit Service db8eaa
	const snd_pcm_uframes_t user_avail = snd_pcm_ioplug_avail(ioplug,
Packit Service db8eaa
								  hw_ptr,
Packit Service db8eaa
								  appl_ptr);
Packit Service db8eaa
Packit Service db8eaa
	if (user_avail > ioplug->pcm->buffer_size) {
Packit Service db8eaa
		/* there was an Xrun */
Packit Service db8eaa
		return 0;
Packit Service db8eaa
	}
Packit Service db8eaa
	/* available data/space which can be transferred by the DMA */
Packit Service db8eaa
	return ioplug->pcm->buffer_size - user_avail;
Packit Service db8eaa
}