162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci *  Linear conversion Plug-In
362306a36Sopenharmony_ci *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *   This library is free software; you can redistribute it and/or modify
762306a36Sopenharmony_ci *   it under the terms of the GNU Library General Public License as
862306a36Sopenharmony_ci *   published by the Free Software Foundation; either version 2 of
962306a36Sopenharmony_ci *   the License, or (at your option) any later version.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *   This program is distributed in the hope that it will be useful,
1262306a36Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
1362306a36Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1462306a36Sopenharmony_ci *   GNU Library General Public License for more details.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci *   You should have received a copy of the GNU Library General Public
1762306a36Sopenharmony_ci *   License along with this library; if not, write to the Free Software
1862306a36Sopenharmony_ci *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <linux/time.h>
2362306a36Sopenharmony_ci#include <sound/core.h>
2462306a36Sopenharmony_ci#include <sound/pcm.h>
2562306a36Sopenharmony_ci#include "pcm_plugin.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic snd_pcm_sframes_t copy_transfer(struct snd_pcm_plugin *plugin,
2862306a36Sopenharmony_ci			     const struct snd_pcm_plugin_channel *src_channels,
2962306a36Sopenharmony_ci			     struct snd_pcm_plugin_channel *dst_channels,
3062306a36Sopenharmony_ci			     snd_pcm_uframes_t frames)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	unsigned int channel;
3362306a36Sopenharmony_ci	unsigned int nchannels;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	if (snd_BUG_ON(!plugin || !src_channels || !dst_channels))
3662306a36Sopenharmony_ci		return -ENXIO;
3762306a36Sopenharmony_ci	if (frames == 0)
3862306a36Sopenharmony_ci		return 0;
3962306a36Sopenharmony_ci	nchannels = plugin->src_format.channels;
4062306a36Sopenharmony_ci	for (channel = 0; channel < nchannels; channel++) {
4162306a36Sopenharmony_ci		if (snd_BUG_ON(src_channels->area.first % 8 ||
4262306a36Sopenharmony_ci			       src_channels->area.step % 8))
4362306a36Sopenharmony_ci			return -ENXIO;
4462306a36Sopenharmony_ci		if (snd_BUG_ON(dst_channels->area.first % 8 ||
4562306a36Sopenharmony_ci			       dst_channels->area.step % 8))
4662306a36Sopenharmony_ci			return -ENXIO;
4762306a36Sopenharmony_ci		if (!src_channels->enabled) {
4862306a36Sopenharmony_ci			if (dst_channels->wanted)
4962306a36Sopenharmony_ci				snd_pcm_area_silence(&dst_channels->area, 0, frames, plugin->dst_format.format);
5062306a36Sopenharmony_ci			dst_channels->enabled = 0;
5162306a36Sopenharmony_ci			continue;
5262306a36Sopenharmony_ci		}
5362306a36Sopenharmony_ci		dst_channels->enabled = 1;
5462306a36Sopenharmony_ci		snd_pcm_area_copy(&src_channels->area, 0, &dst_channels->area, 0, frames, plugin->src_format.format);
5562306a36Sopenharmony_ci		src_channels++;
5662306a36Sopenharmony_ci		dst_channels++;
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci	return frames;
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ciint snd_pcm_plugin_build_copy(struct snd_pcm_substream *plug,
6262306a36Sopenharmony_ci			      struct snd_pcm_plugin_format *src_format,
6362306a36Sopenharmony_ci			      struct snd_pcm_plugin_format *dst_format,
6462306a36Sopenharmony_ci			      struct snd_pcm_plugin **r_plugin)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	int err;
6762306a36Sopenharmony_ci	struct snd_pcm_plugin *plugin;
6862306a36Sopenharmony_ci	int width;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	if (snd_BUG_ON(!r_plugin))
7162306a36Sopenharmony_ci		return -ENXIO;
7262306a36Sopenharmony_ci	*r_plugin = NULL;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	if (snd_BUG_ON(src_format->format != dst_format->format))
7562306a36Sopenharmony_ci		return -ENXIO;
7662306a36Sopenharmony_ci	if (snd_BUG_ON(src_format->rate != dst_format->rate))
7762306a36Sopenharmony_ci		return -ENXIO;
7862306a36Sopenharmony_ci	if (snd_BUG_ON(src_format->channels != dst_format->channels))
7962306a36Sopenharmony_ci		return -ENXIO;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	width = snd_pcm_format_physical_width(src_format->format);
8262306a36Sopenharmony_ci	if (snd_BUG_ON(width <= 0))
8362306a36Sopenharmony_ci		return -ENXIO;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	err = snd_pcm_plugin_build(plug, "copy", src_format, dst_format,
8662306a36Sopenharmony_ci				   0, &plugin);
8762306a36Sopenharmony_ci	if (err < 0)
8862306a36Sopenharmony_ci		return err;
8962306a36Sopenharmony_ci	plugin->transfer = copy_transfer;
9062306a36Sopenharmony_ci	*r_plugin = plugin;
9162306a36Sopenharmony_ci	return 0;
9262306a36Sopenharmony_ci}
93