11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds * PCM I/O Plug-In Interface
3c1017a4cSJaroslav Kysela * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds *
61da177e4SLinus Torvalds * This library is free software; you can redistribute it and/or modify
71da177e4SLinus Torvalds * it under the terms of the GNU Library General Public License as
81da177e4SLinus Torvalds * published by the Free Software Foundation; either version 2 of
91da177e4SLinus Torvalds * the License, or (at your option) any later version.
101da177e4SLinus Torvalds *
111da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful,
121da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of
131da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
141da177e4SLinus Torvalds * GNU Library General Public License for more details.
151da177e4SLinus Torvalds *
161da177e4SLinus Torvalds * You should have received a copy of the GNU Library General Public
171da177e4SLinus Torvalds * License along with this library; if not, write to the Free Software
181da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
191da177e4SLinus Torvalds *
201da177e4SLinus Torvalds */
211da177e4SLinus Torvalds
221da177e4SLinus Torvalds #include <linux/time.h>
231da177e4SLinus Torvalds #include <sound/core.h>
241da177e4SLinus Torvalds #include <sound/pcm.h>
251da177e4SLinus Torvalds #include <sound/pcm_params.h>
261da177e4SLinus Torvalds #include "pcm_plugin.h"
271da177e4SLinus Torvalds
281da177e4SLinus Torvalds #define pcm_write(plug,buf,count) snd_pcm_oss_write3(plug,buf,count,1)
29*fed5794fSTakashi Iwai #define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count)
301da177e4SLinus Torvalds #define pcm_read(plug,buf,count) snd_pcm_oss_read3(plug,buf,count,1)
31*fed5794fSTakashi Iwai #define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count)
321da177e4SLinus Torvalds
331da177e4SLinus Torvalds /*
341da177e4SLinus Torvalds * Basic io plugin
351da177e4SLinus Torvalds */
361da177e4SLinus Torvalds
io_playback_transfer(struct snd_pcm_plugin * plugin,const struct snd_pcm_plugin_channel * src_channels,struct snd_pcm_plugin_channel * dst_channels,snd_pcm_uframes_t frames)376ac77bc1STakashi Iwai static snd_pcm_sframes_t io_playback_transfer(struct snd_pcm_plugin *plugin,
386ac77bc1STakashi Iwai const struct snd_pcm_plugin_channel *src_channels,
396ac77bc1STakashi Iwai struct snd_pcm_plugin_channel *dst_channels,
401da177e4SLinus Torvalds snd_pcm_uframes_t frames)
411da177e4SLinus Torvalds {
427eaa943cSTakashi Iwai if (snd_BUG_ON(!plugin))
437eaa943cSTakashi Iwai return -ENXIO;
447eaa943cSTakashi Iwai if (snd_BUG_ON(!src_channels))
457eaa943cSTakashi Iwai return -ENXIO;
461da177e4SLinus Torvalds if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
471da177e4SLinus Torvalds return pcm_write(plugin->plug, src_channels->area.addr, frames);
481da177e4SLinus Torvalds } else {
491da177e4SLinus Torvalds int channel, channels = plugin->dst_format.channels;
501da177e4SLinus Torvalds void **bufs = (void**)plugin->extra_data;
517eaa943cSTakashi Iwai if (snd_BUG_ON(!bufs))
527eaa943cSTakashi Iwai return -ENXIO;
531da177e4SLinus Torvalds for (channel = 0; channel < channels; channel++) {
541da177e4SLinus Torvalds if (src_channels[channel].enabled)
551da177e4SLinus Torvalds bufs[channel] = src_channels[channel].area.addr;
561da177e4SLinus Torvalds else
571da177e4SLinus Torvalds bufs[channel] = NULL;
581da177e4SLinus Torvalds }
591da177e4SLinus Torvalds return pcm_writev(plugin->plug, bufs, frames);
601da177e4SLinus Torvalds }
611da177e4SLinus Torvalds }
621da177e4SLinus Torvalds
io_capture_transfer(struct snd_pcm_plugin * plugin,const struct snd_pcm_plugin_channel * src_channels,struct snd_pcm_plugin_channel * dst_channels,snd_pcm_uframes_t frames)636ac77bc1STakashi Iwai static snd_pcm_sframes_t io_capture_transfer(struct snd_pcm_plugin *plugin,
646ac77bc1STakashi Iwai const struct snd_pcm_plugin_channel *src_channels,
656ac77bc1STakashi Iwai struct snd_pcm_plugin_channel *dst_channels,
661da177e4SLinus Torvalds snd_pcm_uframes_t frames)
671da177e4SLinus Torvalds {
687eaa943cSTakashi Iwai if (snd_BUG_ON(!plugin))
697eaa943cSTakashi Iwai return -ENXIO;
707eaa943cSTakashi Iwai if (snd_BUG_ON(!dst_channels))
717eaa943cSTakashi Iwai return -ENXIO;
721da177e4SLinus Torvalds if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
731da177e4SLinus Torvalds return pcm_read(plugin->plug, dst_channels->area.addr, frames);
741da177e4SLinus Torvalds } else {
751da177e4SLinus Torvalds int channel, channels = plugin->dst_format.channels;
761da177e4SLinus Torvalds void **bufs = (void**)plugin->extra_data;
777eaa943cSTakashi Iwai if (snd_BUG_ON(!bufs))
787eaa943cSTakashi Iwai return -ENXIO;
791da177e4SLinus Torvalds for (channel = 0; channel < channels; channel++) {
801da177e4SLinus Torvalds if (dst_channels[channel].enabled)
811da177e4SLinus Torvalds bufs[channel] = dst_channels[channel].area.addr;
821da177e4SLinus Torvalds else
831da177e4SLinus Torvalds bufs[channel] = NULL;
841da177e4SLinus Torvalds }
851da177e4SLinus Torvalds return pcm_readv(plugin->plug, bufs, frames);
861da177e4SLinus Torvalds }
871da177e4SLinus Torvalds return 0;
881da177e4SLinus Torvalds }
891da177e4SLinus Torvalds
io_src_channels(struct snd_pcm_plugin * plugin,snd_pcm_uframes_t frames,struct snd_pcm_plugin_channel ** channels)906ac77bc1STakashi Iwai static snd_pcm_sframes_t io_src_channels(struct snd_pcm_plugin *plugin,
911da177e4SLinus Torvalds snd_pcm_uframes_t frames,
926ac77bc1STakashi Iwai struct snd_pcm_plugin_channel **channels)
931da177e4SLinus Torvalds {
941da177e4SLinus Torvalds int err;
951da177e4SLinus Torvalds unsigned int channel;
966ac77bc1STakashi Iwai struct snd_pcm_plugin_channel *v;
971da177e4SLinus Torvalds err = snd_pcm_plugin_client_channels(plugin, frames, &v);
981da177e4SLinus Torvalds if (err < 0)
991da177e4SLinus Torvalds return err;
1001da177e4SLinus Torvalds *channels = v;
1011da177e4SLinus Torvalds if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
1021da177e4SLinus Torvalds for (channel = 0; channel < plugin->src_format.channels; ++channel, ++v)
1031da177e4SLinus Torvalds v->wanted = 1;
1041da177e4SLinus Torvalds }
1051da177e4SLinus Torvalds return frames;
1061da177e4SLinus Torvalds }
1071da177e4SLinus Torvalds
snd_pcm_plugin_build_io(struct snd_pcm_substream * plug,struct snd_pcm_hw_params * params,struct snd_pcm_plugin ** r_plugin)1086ac77bc1STakashi Iwai int snd_pcm_plugin_build_io(struct snd_pcm_substream *plug,
1096ac77bc1STakashi Iwai struct snd_pcm_hw_params *params,
1106ac77bc1STakashi Iwai struct snd_pcm_plugin **r_plugin)
1111da177e4SLinus Torvalds {
1121da177e4SLinus Torvalds int err;
1136ac77bc1STakashi Iwai struct snd_pcm_plugin_format format;
1146ac77bc1STakashi Iwai struct snd_pcm_plugin *plugin;
1151da177e4SLinus Torvalds
1167eaa943cSTakashi Iwai if (snd_BUG_ON(!r_plugin))
1177eaa943cSTakashi Iwai return -ENXIO;
1181da177e4SLinus Torvalds *r_plugin = NULL;
1197eaa943cSTakashi Iwai if (snd_BUG_ON(!plug || !params))
1207eaa943cSTakashi Iwai return -ENXIO;
1211da177e4SLinus Torvalds format.format = params_format(params);
1221da177e4SLinus Torvalds format.rate = params_rate(params);
1231da177e4SLinus Torvalds format.channels = params_channels(params);
1241da177e4SLinus Torvalds err = snd_pcm_plugin_build(plug, "I/O io",
1251da177e4SLinus Torvalds &format, &format,
1261da177e4SLinus Torvalds sizeof(void *) * format.channels,
1271da177e4SLinus Torvalds &plugin);
1281da177e4SLinus Torvalds if (err < 0)
1291da177e4SLinus Torvalds return err;
1301da177e4SLinus Torvalds plugin->access = params_access(params);
1311da177e4SLinus Torvalds if (snd_pcm_plug_stream(plug) == SNDRV_PCM_STREAM_PLAYBACK) {
1321da177e4SLinus Torvalds plugin->transfer = io_playback_transfer;
1331da177e4SLinus Torvalds if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED)
1341da177e4SLinus Torvalds plugin->client_channels = io_src_channels;
1351da177e4SLinus Torvalds } else {
1361da177e4SLinus Torvalds plugin->transfer = io_capture_transfer;
1371da177e4SLinus Torvalds }
1381da177e4SLinus Torvalds
1391da177e4SLinus Torvalds *r_plugin = plugin;
1401da177e4SLinus Torvalds return 0;
1411da177e4SLinus Torvalds }
142