Blame src/pcm/pcm_mmap_emul.c

Packit 4a16fb
/**
Packit 4a16fb
 * \file pcm/pcm_mmap_emul.c
Packit 4a16fb
 * \ingroup PCM_Plugins
Packit 4a16fb
 * \brief PCM Mmap-Emulation Plugin Interface
Packit 4a16fb
 * \author Takashi Iwai <tiwai@suse.de>
Packit 4a16fb
 * \date 2007
Packit 4a16fb
 */
Packit 4a16fb
/*
Packit 4a16fb
 *  PCM - Mmap-Emulation
Packit 4a16fb
 *  Copyright (c) 2007 by Takashi Iwai <tiwai@suse.de>
Packit 4a16fb
 *
Packit 4a16fb
 *
Packit 4a16fb
 *   This library is free software; you can redistribute it and/or modify
Packit 4a16fb
 *   it under the terms of the GNU Lesser General Public License as
Packit 4a16fb
 *   published by the Free Software Foundation; either version 2.1 of
Packit 4a16fb
 *   the License, or (at your option) any later version.
Packit 4a16fb
 *
Packit 4a16fb
 *   This program is distributed in the hope that it will be useful,
Packit 4a16fb
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 4a16fb
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 4a16fb
 *   GNU Lesser General Public License for more details.
Packit 4a16fb
 *
Packit 4a16fb
 *   You should have received a copy of the GNU Lesser General Public
Packit 4a16fb
 *   License along with this library; if not, write to the Free Software
Packit 4a16fb
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit 4a16fb
 *
Packit 4a16fb
 */
Packit 4a16fb
  
Packit 4a16fb
#include "pcm_local.h"
Packit 4a16fb
#include "pcm_generic.h"
Packit 4a16fb
Packit 4a16fb
#ifndef PIC
Packit 4a16fb
/* entry for static linking */
Packit 4a16fb
const char *_snd_module_pcm_mmap_emul = "";
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
#ifndef DOC_HIDDEN
Packit 4a16fb
/*
Packit 4a16fb
 *
Packit 4a16fb
 */
Packit 4a16fb
Packit 4a16fb
typedef struct {
Packit 4a16fb
	snd_pcm_generic_t gen;
Packit 4a16fb
	unsigned int mmap_emul :1;
Packit 4a16fb
	snd_pcm_uframes_t hw_ptr;
Packit 4a16fb
	snd_pcm_uframes_t appl_ptr;
Packit 4a16fb
	snd_pcm_uframes_t start_threshold;
Packit 4a16fb
} mmap_emul_t;
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * here goes a really tricky part; hw_refine falls back to ACCESS_RW_* type
Packit 4a16fb
 * when ACCESS_MMAP_* isn't supported by the hardware.
Packit 4a16fb
 */
Packit 4a16fb
static int snd_pcm_mmap_emul_hw_refine(snd_pcm_t *pcm,
Packit 4a16fb
				       snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	mmap_emul_t *map = pcm->private_data;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
	snd_pcm_access_mask_t oldmask =
Packit 4a16fb
		*snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS);
Packit 4a16fb
	snd_pcm_access_mask_t mask;
Packit 4a16fb
	const snd_mask_t *pmask;
Packit 4a16fb
Packit 4a16fb
	snd_mask_none(&mask);
Packit 4a16fb
	err = snd_pcm_hw_refine(map->gen.slave, params);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		snd_pcm_hw_params_t new = *params;
Packit 4a16fb
Packit 4a16fb
		/* try to use RW_* */
Packit 4a16fb
		if (snd_pcm_access_mask_test(&oldmask,
Packit 4a16fb
					     SND_PCM_ACCESS_MMAP_INTERLEAVED) &&
Packit 4a16fb
		    !snd_pcm_access_mask_test(&oldmask,
Packit 4a16fb
					      SND_PCM_ACCESS_RW_INTERLEAVED))
Packit 4a16fb
			snd_pcm_access_mask_set(&mask,
Packit 4a16fb
						SND_PCM_ACCESS_RW_INTERLEAVED);
Packit 4a16fb
		if (snd_pcm_access_mask_test(&oldmask,
Packit 4a16fb
					     SND_PCM_ACCESS_MMAP_NONINTERLEAVED) &&
Packit 4a16fb
		    !snd_pcm_access_mask_test(&oldmask,
Packit 4a16fb
					      SND_PCM_ACCESS_RW_NONINTERLEAVED))
Packit 4a16fb
			snd_pcm_access_mask_set(&mask,
Packit 4a16fb
						SND_PCM_ACCESS_RW_NONINTERLEAVED);
Packit 4a16fb
		if (snd_pcm_access_mask_empty(&mask))
Packit 4a16fb
			return err;
Packit 4a16fb
		pmask = snd_pcm_hw_param_get_mask(&new,
Packit 4a16fb
						  SND_PCM_HW_PARAM_ACCESS);
Packit 4a16fb
		*(snd_mask_t *)pmask = mask;
Packit 4a16fb
		err = snd_pcm_hw_refine(map->gen.slave, &new;;
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
		*params = new;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	pmask = snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS);
Packit 4a16fb
	if (snd_pcm_access_mask_test(pmask, SND_PCM_ACCESS_MMAP_INTERLEAVED) ||
Packit 4a16fb
	    snd_pcm_access_mask_test(pmask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED) ||
Packit 4a16fb
	    snd_pcm_access_mask_test(pmask, SND_PCM_ACCESS_MMAP_COMPLEX))
Packit 4a16fb
		return 0;
Packit 4a16fb
	if (snd_pcm_access_mask_test(&mask, SND_PCM_ACCESS_RW_INTERLEAVED)) {
Packit 4a16fb
		if (snd_pcm_access_mask_test(pmask,
Packit 4a16fb
					     SND_PCM_ACCESS_RW_INTERLEAVED))
Packit 4a16fb
			snd_pcm_access_mask_set((snd_pcm_access_mask_t *)pmask,
Packit 4a16fb
						SND_PCM_ACCESS_MMAP_INTERLEAVED);
Packit 4a16fb
		snd_pcm_access_mask_reset((snd_pcm_access_mask_t *)pmask,
Packit 4a16fb
					  SND_PCM_ACCESS_RW_INTERLEAVED);
Packit 4a16fb
		params->cmask |= 1<
Packit 4a16fb
	}
Packit 4a16fb
	if (snd_pcm_access_mask_test(&mask, SND_PCM_ACCESS_RW_NONINTERLEAVED)) {
Packit 4a16fb
		if (snd_pcm_access_mask_test(pmask,
Packit 4a16fb
					     SND_PCM_ACCESS_RW_NONINTERLEAVED))
Packit 4a16fb
			snd_pcm_access_mask_set((snd_pcm_access_mask_t *)pmask,
Packit 4a16fb
						SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
Packit 4a16fb
		snd_pcm_access_mask_reset((snd_pcm_access_mask_t *)pmask,
Packit 4a16fb
					  SND_PCM_ACCESS_RW_NONINTERLEAVED);
Packit 4a16fb
		params->cmask |= 1<
Packit 4a16fb
	}
Packit 4a16fb
	if (snd_pcm_access_mask_test(&oldmask, SND_PCM_ACCESS_MMAP_INTERLEAVED)) {
Packit 4a16fb
		if (snd_pcm_access_mask_test(&oldmask,
Packit 4a16fb
					     SND_PCM_ACCESS_RW_INTERLEAVED)) {
Packit 4a16fb
			if (snd_pcm_access_mask_test(pmask,
Packit 4a16fb
						     SND_PCM_ACCESS_RW_INTERLEAVED)) {
Packit 4a16fb
				snd_pcm_access_mask_set((snd_pcm_access_mask_t *)pmask,
Packit 4a16fb
							SND_PCM_ACCESS_MMAP_INTERLEAVED);
Packit 4a16fb
				params->cmask |= 1<
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	if (snd_pcm_access_mask_test(&oldmask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) {
Packit 4a16fb
		if (snd_pcm_access_mask_test(&oldmask,
Packit 4a16fb
					     SND_PCM_ACCESS_RW_NONINTERLEAVED)) {
Packit 4a16fb
			if (snd_pcm_access_mask_test(pmask,
Packit 4a16fb
						     SND_PCM_ACCESS_RW_NONINTERLEAVED)) {
Packit 4a16fb
				snd_pcm_access_mask_set((snd_pcm_access_mask_t *)pmask,
Packit 4a16fb
							SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
Packit 4a16fb
				params->cmask |= 1<
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * hw_params needs a similar hack like hw_refine, but it's much simpler
Packit 4a16fb
 * because now snd_pcm_hw_params_t takes only one choice for each item.
Packit 4a16fb
 *
Packit 4a16fb
 * Here, when the normal hw_params call fails, it turns on the mmap_emul
Packit 4a16fb
 * flag and tries to use ACCESS_RW_* mode.
Packit 4a16fb
 *
Packit 4a16fb
 * In mmap_emul mode, the appl_ptr and hw_ptr are handled individually
Packit 4a16fb
 * from the layering slave PCM, and they are sync'ed appropriately in
Packit 4a16fb
 * each read/write or avail_update/commit call.
Packit 4a16fb
 */
Packit 4a16fb
static int snd_pcm_mmap_emul_hw_params(snd_pcm_t *pcm,
Packit 4a16fb
				       snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	mmap_emul_t *map = pcm->private_data;
Packit 4a16fb
	snd_pcm_hw_params_t old = *params;
Packit 4a16fb
	snd_pcm_access_t access;
Packit 4a16fb
	snd_pcm_access_mask_t oldmask;
Packit 4a16fb
	snd_pcm_access_mask_t *pmask;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	err = _snd_pcm_hw_params_internal(map->gen.slave, params);
Packit 4a16fb
	if (err >= 0) {
Packit 4a16fb
		map->mmap_emul = 0;
Packit 4a16fb
		return err;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	*params = old;
Packit 4a16fb
	pmask = (snd_pcm_access_mask_t *)snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS);
Packit 4a16fb
	oldmask = *pmask;
Packit 4a16fb
	if (INTERNAL(snd_pcm_hw_params_get_access)(params, &access) < 0)
Packit 4a16fb
		goto _err;
Packit 4a16fb
	switch (access) {
Packit 4a16fb
	case SND_PCM_ACCESS_MMAP_INTERLEAVED:
Packit 4a16fb
		snd_pcm_access_mask_reset(pmask,
Packit 4a16fb
					  SND_PCM_ACCESS_MMAP_INTERLEAVED);
Packit 4a16fb
		snd_pcm_access_mask_set(pmask, SND_PCM_ACCESS_RW_INTERLEAVED);
Packit 4a16fb
		break;
Packit 4a16fb
	case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
Packit 4a16fb
		snd_pcm_access_mask_reset(pmask,
Packit 4a16fb
					  SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
Packit 4a16fb
		snd_pcm_access_mask_set(pmask,
Packit 4a16fb
					SND_PCM_ACCESS_RW_NONINTERLEAVED);
Packit 4a16fb
		break;
Packit 4a16fb
	default:
Packit 4a16fb
		goto _err;
Packit 4a16fb
	}
Packit 4a16fb
	err = _snd_pcm_hw_params_internal(map->gen.slave, params);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		goto _err;
Packit 4a16fb
Packit 4a16fb
	/* need to back the access type to relieve apps */
Packit 4a16fb
	*pmask = oldmask;
Packit 4a16fb
Packit 4a16fb
	/* OK, we do fake */
Packit 4a16fb
	map->mmap_emul = 1;
Packit 4a16fb
	map->appl_ptr = 0;
Packit 4a16fb
	map->hw_ptr = 0;
Packit 4a16fb
	snd_pcm_set_hw_ptr(pcm, &map->hw_ptr, -1, 0);
Packit 4a16fb
	snd_pcm_set_appl_ptr(pcm, &map->appl_ptr, -1, 0);
Packit 4a16fb
	return 0;
Packit 4a16fb
Packit 4a16fb
 _err:
Packit 4a16fb
	err = -errno;
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_mmap_emul_sw_params(snd_pcm_t *pcm,
Packit 4a16fb
				       snd_pcm_sw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	mmap_emul_t *map = pcm->private_data;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	if (!map->mmap_emul)
Packit 4a16fb
		return snd_pcm_generic_sw_params(pcm, params);
Packit 4a16fb
Packit 4a16fb
	map->start_threshold = params->start_threshold;
Packit 4a16fb
Packit 4a16fb
	/* HACK: don't auto-start in the slave PCM */
Packit 4a16fb
	params->start_threshold = pcm->boundary;
Packit 4a16fb
	err = snd_pcm_generic_sw_params(pcm, params);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	/* restore the value for this PCM */
Packit 4a16fb
	params->start_threshold = map->start_threshold;
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_mmap_emul_prepare(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	mmap_emul_t *map = pcm->private_data;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	err = snd_pcm_generic_prepare(pcm);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	map->hw_ptr = map->appl_ptr = 0;
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_mmap_emul_reset(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	mmap_emul_t *map = pcm->private_data;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	err = snd_pcm_generic_reset(pcm);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	map->hw_ptr = map->appl_ptr = 0;
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t
Packit 4a16fb
snd_pcm_mmap_emul_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
Packit 4a16fb
{
Packit 4a16fb
	frames = snd_pcm_generic_rewind(pcm, frames);
Packit 4a16fb
	if (frames > 0)
Packit 4a16fb
		snd_pcm_mmap_appl_backward(pcm, frames);
Packit 4a16fb
	return frames;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t
Packit 4a16fb
snd_pcm_mmap_emul_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
Packit 4a16fb
{
Packit 4a16fb
	frames = snd_pcm_generic_forward(pcm, frames);
Packit 4a16fb
	if (frames > 0)
Packit 4a16fb
		snd_pcm_mmap_appl_forward(pcm, frames);
Packit 4a16fb
	return frames;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* write out the uncommitted chunk on mmap buffer to the slave PCM */
Packit 4a16fb
static snd_pcm_sframes_t
Packit 4a16fb
sync_slave_write(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	mmap_emul_t *map = pcm->private_data;
Packit 4a16fb
	snd_pcm_t *slave = map->gen.slave;
Packit 4a16fb
	snd_pcm_uframes_t offset;
Packit 4a16fb
	snd_pcm_sframes_t size;
Packit 4a16fb
Packit 4a16fb
	/* HACK: don't start stream automatically at commit in mmap mode */
Packit 4a16fb
	pcm->start_threshold = pcm->boundary;
Packit 4a16fb
Packit 4a16fb
	size = map->appl_ptr - *slave->appl.ptr;
Packit 4a16fb
	if (size < 0)
Packit 4a16fb
		size += pcm->boundary;
Packit 4a16fb
	if (size) {
Packit 4a16fb
		offset = *slave->appl.ptr % pcm->buffer_size;
Packit 4a16fb
		size = snd_pcm_write_mmap(pcm, offset, size);
Packit 4a16fb
	}
Packit 4a16fb
	pcm->start_threshold = map->start_threshold; /* restore */
Packit 4a16fb
	return size;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* read the available chunk on the slave PCM to mmap buffer */
Packit 4a16fb
static snd_pcm_sframes_t
Packit 4a16fb
sync_slave_read(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	mmap_emul_t *map = pcm->private_data;
Packit 4a16fb
	snd_pcm_t *slave = map->gen.slave;
Packit 4a16fb
	snd_pcm_uframes_t offset;
Packit 4a16fb
	snd_pcm_sframes_t size;
Packit 4a16fb
Packit 4a16fb
	size = *slave->hw.ptr - map->hw_ptr;
Packit 4a16fb
	if (size < 0)
Packit 4a16fb
		size += pcm->boundary;
Packit 4a16fb
	if (!size)
Packit 4a16fb
		return 0;
Packit 4a16fb
	offset = map->hw_ptr % pcm->buffer_size;
Packit 4a16fb
	size = snd_pcm_read_mmap(pcm, offset, size);
Packit 4a16fb
	if (size > 0)
Packit 4a16fb
		snd_pcm_mmap_hw_forward(pcm, size);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t
Packit 4a16fb
snd_pcm_mmap_emul_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset,
Packit 4a16fb
			      snd_pcm_uframes_t size)
Packit 4a16fb
{
Packit 4a16fb
	mmap_emul_t *map = pcm->private_data;
Packit 4a16fb
	snd_pcm_t *slave = map->gen.slave;
Packit 4a16fb
Packit 4a16fb
	snd_pcm_mmap_appl_forward(pcm, size);
Packit 4a16fb
	if (!map->mmap_emul)
Packit 4a16fb
		return snd_pcm_mmap_commit(slave, offset, size);
Packit 4a16fb
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
Packit 4a16fb
		sync_slave_write(pcm);
Packit 4a16fb
	return size;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static snd_pcm_sframes_t snd_pcm_mmap_emul_avail_update(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	mmap_emul_t *map = pcm->private_data;
Packit 4a16fb
	snd_pcm_t *slave = map->gen.slave;
Packit 4a16fb
Packit 4a16fb
	if (!map->mmap_emul || pcm->stream == SND_PCM_STREAM_PLAYBACK)
Packit 4a16fb
		map->hw_ptr = *slave->hw.ptr;
Packit 4a16fb
	else
Packit 4a16fb
		sync_slave_read(pcm);
Packit 4a16fb
	return snd_pcm_mmap_avail(pcm);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void snd_pcm_mmap_emul_dump(snd_pcm_t *pcm, snd_output_t *out)
Packit 4a16fb
{
Packit 4a16fb
	mmap_emul_t *map = pcm->private_data;
Packit 4a16fb
Packit 4a16fb
	snd_output_printf(out, "Mmap emulation PCM\n");
Packit 4a16fb
	if (pcm->setup) {
Packit 4a16fb
		snd_output_printf(out, "Its setup is:\n");
Packit 4a16fb
		snd_pcm_dump_setup(pcm, out);
Packit 4a16fb
	}
Packit 4a16fb
	snd_output_printf(out, "Slave: ");
Packit 4a16fb
	snd_pcm_dump(map->gen.slave, out);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static const snd_pcm_ops_t snd_pcm_mmap_emul_ops = {
Packit 4a16fb
	.close = snd_pcm_generic_close,
Packit 4a16fb
	.info = snd_pcm_generic_info,
Packit 4a16fb
	.hw_refine = snd_pcm_mmap_emul_hw_refine,
Packit 4a16fb
	.hw_params = snd_pcm_mmap_emul_hw_params,
Packit 4a16fb
	.hw_free = snd_pcm_generic_hw_free,
Packit 4a16fb
	.sw_params = snd_pcm_mmap_emul_sw_params,
Packit 4a16fb
	.channel_info = snd_pcm_generic_channel_info,
Packit 4a16fb
	.dump = snd_pcm_mmap_emul_dump,
Packit 4a16fb
	.nonblock = snd_pcm_generic_nonblock,
Packit 4a16fb
	.async = snd_pcm_generic_async,
Packit 4a16fb
	.mmap = snd_pcm_generic_mmap,
Packit 4a16fb
	.munmap = snd_pcm_generic_munmap,
Packit 4a16fb
	.query_chmaps = snd_pcm_generic_query_chmaps,
Packit 4a16fb
	.get_chmap = snd_pcm_generic_get_chmap,
Packit 4a16fb
	.set_chmap = snd_pcm_generic_set_chmap,
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
static const snd_pcm_fast_ops_t snd_pcm_mmap_emul_fast_ops = {
Packit 4a16fb
	.status = snd_pcm_generic_status,
Packit 4a16fb
	.state = snd_pcm_generic_state,
Packit 4a16fb
	.hwsync = snd_pcm_generic_hwsync,
Packit 4a16fb
	.delay = snd_pcm_generic_delay,
Packit 4a16fb
	.prepare = snd_pcm_mmap_emul_prepare,
Packit 4a16fb
	.reset = snd_pcm_mmap_emul_reset,
Packit 4a16fb
	.start = snd_pcm_generic_start,
Packit 4a16fb
	.drop = snd_pcm_generic_drop,
Packit 4a16fb
	.drain = snd_pcm_generic_drain,
Packit 4a16fb
	.pause = snd_pcm_generic_pause,
Packit 4a16fb
	.rewindable = snd_pcm_generic_rewindable,
Packit 4a16fb
	.rewind = snd_pcm_mmap_emul_rewind,
Packit 4a16fb
	.forwardable = snd_pcm_generic_forwardable,
Packit 4a16fb
	.forward = snd_pcm_mmap_emul_forward,
Packit 4a16fb
	.resume = snd_pcm_generic_resume,
Packit 4a16fb
	.link = snd_pcm_generic_link,
Packit 4a16fb
	.link_slaves = snd_pcm_generic_link_slaves,
Packit 4a16fb
	.unlink = snd_pcm_generic_unlink,
Packit 4a16fb
	.writei = snd_pcm_generic_writei,
Packit 4a16fb
	.writen = snd_pcm_generic_writen,
Packit 4a16fb
	.readi = snd_pcm_generic_readi,
Packit 4a16fb
	.readn = snd_pcm_generic_readn,
Packit 4a16fb
	.avail_update = snd_pcm_mmap_emul_avail_update,
Packit 4a16fb
	.mmap_commit = snd_pcm_mmap_emul_mmap_commit,
Packit 4a16fb
	.htimestamp = snd_pcm_generic_htimestamp,
Packit 4a16fb
	.poll_descriptors = snd_pcm_generic_poll_descriptors,
Packit 4a16fb
	.poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
Packit 4a16fb
	.poll_revents = snd_pcm_generic_poll_revents,
Packit 4a16fb
	.may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min,
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
#ifndef DOC_HIDDEN
Packit 4a16fb
int __snd_pcm_mmap_emul_open(snd_pcm_t **pcmp, const char *name,
Packit 4a16fb
			     snd_pcm_t *slave, int close_slave)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_t *pcm;
Packit 4a16fb
	mmap_emul_t *map;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	map = calloc(1, sizeof(*map));
Packit 4a16fb
	if (!map)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
	map->gen.slave = slave;
Packit 4a16fb
	map->gen.close_slave = close_slave;
Packit 4a16fb
Packit 4a16fb
	err = snd_pcm_new(&pcm, SND_PCM_TYPE_MMAP_EMUL, name,
Packit 4a16fb
			  slave->stream, slave->mode);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		free(map);
Packit 4a16fb
		return err;
Packit 4a16fb
	}
Packit 4a16fb
	pcm->ops = &snd_pcm_mmap_emul_ops;
Packit 4a16fb
	pcm->fast_ops = &snd_pcm_mmap_emul_fast_ops;
Packit 4a16fb
	pcm->private_data = map;
Packit 4a16fb
	pcm->poll_fd = slave->poll_fd;
Packit 4a16fb
	pcm->poll_events = slave->poll_events;
Packit 4a16fb
	pcm->tstamp_type = slave->tstamp_type;
Packit 4a16fb
	snd_pcm_set_hw_ptr(pcm, &map->hw_ptr, -1, 0);
Packit 4a16fb
	snd_pcm_set_appl_ptr(pcm, &map->appl_ptr, -1, 0);
Packit 4a16fb
	*pcmp = pcm;
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
/*! \page pcm_plugins
Packit 4a16fb
Packit 4a16fb
\section pcm_plugins_mmap_emul Plugin: mmap_emul
Packit 4a16fb
Packit 4a16fb
\code
Packit 4a16fb
pcm.name {
Packit 4a16fb
	type mmap_emul
Packit 4a16fb
	slave PCM
Packit 4a16fb
}
Packit 4a16fb
\endcode
Packit 4a16fb
Packit 4a16fb
\subsection pcm_plugins_mmap_emul_funcref Function reference
Packit 4a16fb
Packit 4a16fb
    Packit 4a16fb
      
  • _snd_pcm_hw_open()
  • Packit 4a16fb
    Packit 4a16fb
    Packit 4a16fb
    */
    Packit 4a16fb
    Packit 4a16fb
    /**
    Packit 4a16fb
     * \brief Creates a new mmap_emul PCM
    Packit 4a16fb
     * \param pcmp Returns created PCM handle
    Packit 4a16fb
     * \param name Name of PCM
    Packit 4a16fb
     * \param root Root configuration node
    Packit 4a16fb
     * \param conf Configuration node with hw PCM description
    Packit 4a16fb
     * \param stream PCM Stream
    Packit 4a16fb
     * \param mode PCM Mode
    Packit 4a16fb
     * \warning Using of this function might be dangerous in the sense
    Packit 4a16fb
     *          of compatibility reasons. The prototype might be freely
    Packit 4a16fb
     *          changed in future.
    Packit 4a16fb
     */
    Packit 4a16fb
    int _snd_pcm_mmap_emul_open(snd_pcm_t **pcmp, const char *name,
    Packit 4a16fb
    			    snd_config_t *root ATTRIBUTE_UNUSED,
    Packit 4a16fb
    			    snd_config_t *conf,
    Packit 4a16fb
    			    snd_pcm_stream_t stream, int mode)
    Packit 4a16fb
    {
    Packit 4a16fb
    	snd_config_iterator_t i, next;
    Packit 4a16fb
    	int err;
    Packit 4a16fb
    	snd_pcm_t *spcm;
    Packit 4a16fb
    	snd_config_t *slave = NULL, *sconf;
    Packit 4a16fb
    Packit 4a16fb
    	snd_config_for_each(i, next, conf) {
    Packit 4a16fb
    		snd_config_t *n = snd_config_iterator_entry(i);
    Packit 4a16fb
    		const char *id;
    Packit 4a16fb
    		if (snd_config_get_id(n, &id) < 0)
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		if (snd_pcm_conf_generic_id(id))
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		if (strcmp(id, "slave") == 0) {
    Packit 4a16fb
    			slave = n;
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		SNDERR("Unknown field %s", id);
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	if (!slave) {
    Packit 4a16fb
    		SNDERR("slave is not defined");
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	err = snd_pcm_slave_conf(root, slave, &sconf, 0);
    Packit 4a16fb
    	if (err < 0)
    Packit 4a16fb
    		return err;
    Packit 4a16fb
    	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
    Packit 4a16fb
    	snd_config_delete(sconf);
    Packit 4a16fb
    	if (err < 0)
    Packit 4a16fb
    		return err;
    Packit 4a16fb
    	err = __snd_pcm_mmap_emul_open(pcmp, name, spcm, 1);
    Packit 4a16fb
    	if (err < 0)
    Packit 4a16fb
    		snd_pcm_close(spcm);
    Packit 4a16fb
    	return err;
    Packit 4a16fb
    }
    Packit 4a16fb
    Packit 4a16fb
    #ifndef DOC_HIDDEN
    Packit 4a16fb
    SND_DLSYM_BUILD_VERSION(_snd_pcm_mmap_emul_open, SND_PCM_DLSYM_VERSION);
    Packit 4a16fb
    #endif