1 // SPDX-License-Identifier: LGPL-2.0+ 2 /* 3 * PCM I/O Plug-In Interface 4 * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> 5 */ 6 7 #include <linux/time.h> 8 #include <sound/core.h> 9 #include <sound/pcm.h> 10 #include <sound/pcm_params.h> 11 #include "pcm_plugin.h" 12 13 #define pcm_write(plug,buf,count) snd_pcm_oss_write3(plug,buf,count,1) 14 #define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count) 15 #define pcm_read(plug,buf,count) snd_pcm_oss_read3(plug,buf,count,1) 16 #define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count) 17 18 /* 19 * Basic io plugin 20 */ 21 22 static snd_pcm_sframes_t io_playback_transfer(struct snd_pcm_plugin *plugin, 23 const struct snd_pcm_plugin_channel *src_channels, 24 struct snd_pcm_plugin_channel *dst_channels, 25 snd_pcm_uframes_t frames) 26 { 27 if (snd_BUG_ON(!plugin)) 28 return -ENXIO; 29 if (snd_BUG_ON(!src_channels)) 30 return -ENXIO; 31 if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { 32 return pcm_write(plugin->plug, src_channels->area.addr, frames); 33 } else { 34 int channel, channels = plugin->dst_format.channels; 35 void **bufs = (void**)plugin->extra_data; 36 if (snd_BUG_ON(!bufs)) 37 return -ENXIO; 38 for (channel = 0; channel < channels; channel++) { 39 if (src_channels[channel].enabled) 40 bufs[channel] = src_channels[channel].area.addr; 41 else 42 bufs[channel] = NULL; 43 } 44 return pcm_writev(plugin->plug, bufs, frames); 45 } 46 } 47 48 static snd_pcm_sframes_t io_capture_transfer(struct snd_pcm_plugin *plugin, 49 const struct snd_pcm_plugin_channel *src_channels, 50 struct snd_pcm_plugin_channel *dst_channels, 51 snd_pcm_uframes_t frames) 52 { 53 if (snd_BUG_ON(!plugin)) 54 return -ENXIO; 55 if (snd_BUG_ON(!dst_channels)) 56 return -ENXIO; 57 if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { 58 return pcm_read(plugin->plug, dst_channels->area.addr, frames); 59 } else { 60 int channel, channels = plugin->dst_format.channels; 61 void **bufs = (void**)plugin->extra_data; 62 if (snd_BUG_ON(!bufs)) 63 return -ENXIO; 64 for (channel = 0; channel < channels; channel++) { 65 if (dst_channels[channel].enabled) 66 bufs[channel] = dst_channels[channel].area.addr; 67 else 68 bufs[channel] = NULL; 69 } 70 return pcm_readv(plugin->plug, bufs, frames); 71 } 72 return 0; 73 } 74 75 static snd_pcm_sframes_t io_src_channels(struct snd_pcm_plugin *plugin, 76 snd_pcm_uframes_t frames, 77 struct snd_pcm_plugin_channel **channels) 78 { 79 int err; 80 unsigned int channel; 81 struct snd_pcm_plugin_channel *v; 82 err = snd_pcm_plugin_client_channels(plugin, frames, &v); 83 if (err < 0) 84 return err; 85 *channels = v; 86 if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { 87 for (channel = 0; channel < plugin->src_format.channels; ++channel, ++v) 88 v->wanted = 1; 89 } 90 return frames; 91 } 92 93 int snd_pcm_plugin_build_io(struct snd_pcm_substream *plug, 94 struct snd_pcm_hw_params *params, 95 struct snd_pcm_plugin **r_plugin) 96 { 97 int err; 98 struct snd_pcm_plugin_format format; 99 struct snd_pcm_plugin *plugin; 100 101 if (snd_BUG_ON(!r_plugin)) 102 return -ENXIO; 103 *r_plugin = NULL; 104 if (snd_BUG_ON(!plug || !params)) 105 return -ENXIO; 106 format.format = params_format(params); 107 format.rate = params_rate(params); 108 format.channels = params_channels(params); 109 err = snd_pcm_plugin_build(plug, "I/O io", 110 &format, &format, 111 sizeof(void *) * format.channels, 112 &plugin); 113 if (err < 0) 114 return err; 115 plugin->access = params_access(params); 116 if (snd_pcm_plug_stream(plug) == SNDRV_PCM_STREAM_PLAYBACK) { 117 plugin->transfer = io_playback_transfer; 118 if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) 119 plugin->client_channels = io_src_channels; 120 } else { 121 plugin->transfer = io_capture_transfer; 122 } 123 124 *r_plugin = plugin; 125 return 0; 126 } 127