1597603d6SJaroslav Kysela /* 2597603d6SJaroslav Kysela * Loopback soundcard 3597603d6SJaroslav Kysela * 4597603d6SJaroslav Kysela * Original code: 5597603d6SJaroslav Kysela * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 6597603d6SJaroslav Kysela * 7597603d6SJaroslav Kysela * More accurate positioning and full-duplex support: 8597603d6SJaroslav Kysela * Copyright (c) Ahmet İnan <ainan at mathematik.uni-freiburg.de> 9597603d6SJaroslav Kysela * 10597603d6SJaroslav Kysela * Major (almost complete) rewrite: 11597603d6SJaroslav Kysela * Copyright (c) by Takashi Iwai <tiwai@suse.de> 12597603d6SJaroslav Kysela * 13597603d6SJaroslav Kysela * A next major update in 2010 (separate timers for playback and capture): 14597603d6SJaroslav Kysela * Copyright (c) Jaroslav Kysela <perex@perex.cz> 15597603d6SJaroslav Kysela * 16597603d6SJaroslav Kysela * This program is free software; you can redistribute it and/or modify 17597603d6SJaroslav Kysela * it under the terms of the GNU General Public License as published by 18597603d6SJaroslav Kysela * the Free Software Foundation; either version 2 of the License, or 19597603d6SJaroslav Kysela * (at your option) any later version. 20597603d6SJaroslav Kysela * 21597603d6SJaroslav Kysela * This program is distributed in the hope that it will be useful, 22597603d6SJaroslav Kysela * but WITHOUT ANY WARRANTY; without even the implied warranty of 23597603d6SJaroslav Kysela * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24597603d6SJaroslav Kysela * GNU General Public License for more details. 25597603d6SJaroslav Kysela * 26597603d6SJaroslav Kysela * You should have received a copy of the GNU General Public License 27597603d6SJaroslav Kysela * along with this program; if not, write to the Free Software 28597603d6SJaroslav Kysela * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 29597603d6SJaroslav Kysela * 30597603d6SJaroslav Kysela */ 31597603d6SJaroslav Kysela 32597603d6SJaroslav Kysela #include <linux/init.h> 33597603d6SJaroslav Kysela #include <linux/jiffies.h> 34597603d6SJaroslav Kysela #include <linux/slab.h> 35597603d6SJaroslav Kysela #include <linux/time.h> 36597603d6SJaroslav Kysela #include <linux/wait.h> 37597603d6SJaroslav Kysela #include <linux/moduleparam.h> 38597603d6SJaroslav Kysela #include <linux/platform_device.h> 39597603d6SJaroslav Kysela #include <sound/core.h> 40597603d6SJaroslav Kysela #include <sound/control.h> 41597603d6SJaroslav Kysela #include <sound/pcm.h> 42597603d6SJaroslav Kysela #include <sound/initval.h> 43597603d6SJaroslav Kysela 44597603d6SJaroslav Kysela MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 45597603d6SJaroslav Kysela MODULE_DESCRIPTION("A loopback soundcard"); 46597603d6SJaroslav Kysela MODULE_LICENSE("GPL"); 47597603d6SJaroslav Kysela MODULE_SUPPORTED_DEVICE("{{ALSA,Loopback soundcard}}"); 48597603d6SJaroslav Kysela 49597603d6SJaroslav Kysela #define MAX_PCM_SUBSTREAMS 8 50597603d6SJaroslav Kysela 51597603d6SJaroslav Kysela static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 52597603d6SJaroslav Kysela static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 53597603d6SJaroslav Kysela static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; 54597603d6SJaroslav Kysela static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; 55597603d6SJaroslav Kysela static int pcm_notify[SNDRV_CARDS]; 56597603d6SJaroslav Kysela 57597603d6SJaroslav Kysela module_param_array(index, int, NULL, 0444); 58597603d6SJaroslav Kysela MODULE_PARM_DESC(index, "Index value for loopback soundcard."); 59597603d6SJaroslav Kysela module_param_array(id, charp, NULL, 0444); 60597603d6SJaroslav Kysela MODULE_PARM_DESC(id, "ID string for loopback soundcard."); 61597603d6SJaroslav Kysela module_param_array(enable, bool, NULL, 0444); 62597603d6SJaroslav Kysela MODULE_PARM_DESC(enable, "Enable this loopback soundcard."); 63597603d6SJaroslav Kysela module_param_array(pcm_substreams, int, NULL, 0444); 64597603d6SJaroslav Kysela MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver."); 65597603d6SJaroslav Kysela module_param_array(pcm_notify, int, NULL, 0444); 66597603d6SJaroslav Kysela MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes."); 67597603d6SJaroslav Kysela 68597603d6SJaroslav Kysela #define NO_PITCH 100000 69597603d6SJaroslav Kysela 70597603d6SJaroslav Kysela struct loopback_pcm; 71597603d6SJaroslav Kysela 72597603d6SJaroslav Kysela struct loopback_cable { 73597603d6SJaroslav Kysela spinlock_t lock; 74597603d6SJaroslav Kysela struct loopback_pcm *streams[2]; 75597603d6SJaroslav Kysela struct snd_pcm_hardware hw; 76597603d6SJaroslav Kysela /* flags */ 77597603d6SJaroslav Kysela unsigned int valid; 78597603d6SJaroslav Kysela unsigned int running; 79597603d6SJaroslav Kysela }; 80597603d6SJaroslav Kysela 81597603d6SJaroslav Kysela struct loopback_setup { 82597603d6SJaroslav Kysela unsigned int notify: 1; 83597603d6SJaroslav Kysela unsigned int rate_shift; 84597603d6SJaroslav Kysela unsigned int format; 85597603d6SJaroslav Kysela unsigned int rate; 86597603d6SJaroslav Kysela unsigned int channels; 87597603d6SJaroslav Kysela struct snd_ctl_elem_id active_id; 88597603d6SJaroslav Kysela struct snd_ctl_elem_id format_id; 89597603d6SJaroslav Kysela struct snd_ctl_elem_id rate_id; 90597603d6SJaroslav Kysela struct snd_ctl_elem_id channels_id; 91597603d6SJaroslav Kysela }; 92597603d6SJaroslav Kysela 93597603d6SJaroslav Kysela struct loopback { 94597603d6SJaroslav Kysela struct snd_card *card; 95597603d6SJaroslav Kysela struct mutex cable_lock; 96597603d6SJaroslav Kysela struct loopback_cable *cables[MAX_PCM_SUBSTREAMS][2]; 97597603d6SJaroslav Kysela struct snd_pcm *pcm[2]; 98597603d6SJaroslav Kysela struct loopback_setup setup[MAX_PCM_SUBSTREAMS][2]; 99597603d6SJaroslav Kysela }; 100597603d6SJaroslav Kysela 101597603d6SJaroslav Kysela struct loopback_pcm { 102597603d6SJaroslav Kysela struct loopback *loopback; 103597603d6SJaroslav Kysela struct snd_pcm_substream *substream; 104597603d6SJaroslav Kysela struct loopback_cable *cable; 105597603d6SJaroslav Kysela unsigned int pcm_buffer_size; 106597603d6SJaroslav Kysela unsigned int buf_pos; /* position in buffer */ 107597603d6SJaroslav Kysela unsigned int silent_size; 108597603d6SJaroslav Kysela /* PCM parameters */ 109597603d6SJaroslav Kysela unsigned int pcm_period_size; 110597603d6SJaroslav Kysela unsigned int pcm_bps; /* bytes per second */ 111597603d6SJaroslav Kysela unsigned int pcm_salign; /* bytes per sample * channels */ 112597603d6SJaroslav Kysela unsigned int pcm_rate_shift; /* rate shift value */ 113597603d6SJaroslav Kysela /* flags */ 114597603d6SJaroslav Kysela unsigned int period_update_pending :1; 115597603d6SJaroslav Kysela /* timer stuff */ 116597603d6SJaroslav Kysela unsigned int irq_pos; /* fractional IRQ position */ 117597603d6SJaroslav Kysela unsigned int period_size_frac; 118597603d6SJaroslav Kysela unsigned long last_jiffies; 119597603d6SJaroslav Kysela struct timer_list timer; 120597603d6SJaroslav Kysela }; 121597603d6SJaroslav Kysela 122597603d6SJaroslav Kysela static struct platform_device *devices[SNDRV_CARDS]; 123597603d6SJaroslav Kysela 124597603d6SJaroslav Kysela static inline unsigned int byte_pos(struct loopback_pcm *dpcm, unsigned int x) 125597603d6SJaroslav Kysela { 126597603d6SJaroslav Kysela if (dpcm->pcm_rate_shift == NO_PITCH) { 127597603d6SJaroslav Kysela x /= HZ; 128597603d6SJaroslav Kysela } else { 129597603d6SJaroslav Kysela x = div_u64(NO_PITCH * (unsigned long long)x, 130597603d6SJaroslav Kysela HZ * (unsigned long long)dpcm->pcm_rate_shift); 131597603d6SJaroslav Kysela } 132597603d6SJaroslav Kysela return x - (x % dpcm->pcm_salign); 133597603d6SJaroslav Kysela } 134597603d6SJaroslav Kysela 135597603d6SJaroslav Kysela static inline unsigned int frac_pos(struct loopback_pcm *dpcm, unsigned int x) 136597603d6SJaroslav Kysela { 137597603d6SJaroslav Kysela if (dpcm->pcm_rate_shift == NO_PITCH) { /* no pitch */ 138597603d6SJaroslav Kysela return x * HZ; 139597603d6SJaroslav Kysela } else { 140597603d6SJaroslav Kysela x = div_u64(dpcm->pcm_rate_shift * (unsigned long long)x * HZ, 141597603d6SJaroslav Kysela NO_PITCH); 142597603d6SJaroslav Kysela } 143597603d6SJaroslav Kysela return x; 144597603d6SJaroslav Kysela } 145597603d6SJaroslav Kysela 146597603d6SJaroslav Kysela static inline struct loopback_setup *get_setup(struct loopback_pcm *dpcm) 147597603d6SJaroslav Kysela { 148597603d6SJaroslav Kysela int device = dpcm->substream->pstr->pcm->device; 149597603d6SJaroslav Kysela 150597603d6SJaroslav Kysela if (dpcm->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 151597603d6SJaroslav Kysela device ^= 1; 152597603d6SJaroslav Kysela return &dpcm->loopback->setup[dpcm->substream->number][device]; 153597603d6SJaroslav Kysela } 154597603d6SJaroslav Kysela 155597603d6SJaroslav Kysela static inline unsigned int get_notify(struct loopback_pcm *dpcm) 156597603d6SJaroslav Kysela { 157597603d6SJaroslav Kysela return get_setup(dpcm)->notify; 158597603d6SJaroslav Kysela } 159597603d6SJaroslav Kysela 160597603d6SJaroslav Kysela static inline unsigned int get_rate_shift(struct loopback_pcm *dpcm) 161597603d6SJaroslav Kysela { 162597603d6SJaroslav Kysela return get_setup(dpcm)->rate_shift; 163597603d6SJaroslav Kysela } 164597603d6SJaroslav Kysela 165597603d6SJaroslav Kysela static void loopback_timer_start(struct loopback_pcm *dpcm) 166597603d6SJaroslav Kysela { 167597603d6SJaroslav Kysela unsigned long tick; 168597603d6SJaroslav Kysela unsigned int rate_shift = get_rate_shift(dpcm); 169597603d6SJaroslav Kysela 170597603d6SJaroslav Kysela if (rate_shift != dpcm->pcm_rate_shift) { 171597603d6SJaroslav Kysela dpcm->pcm_rate_shift = rate_shift; 172597603d6SJaroslav Kysela dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size); 173597603d6SJaroslav Kysela } 174597603d6SJaroslav Kysela tick = dpcm->period_size_frac - dpcm->irq_pos; 175597603d6SJaroslav Kysela tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps; 176597603d6SJaroslav Kysela dpcm->timer.expires = jiffies + tick; 177597603d6SJaroslav Kysela add_timer(&dpcm->timer); 178597603d6SJaroslav Kysela } 179597603d6SJaroslav Kysela 180597603d6SJaroslav Kysela static inline void loopback_timer_stop(struct loopback_pcm *dpcm) 181597603d6SJaroslav Kysela { 182597603d6SJaroslav Kysela del_timer(&dpcm->timer); 183597603d6SJaroslav Kysela } 184597603d6SJaroslav Kysela 185597603d6SJaroslav Kysela #define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK) 186597603d6SJaroslav Kysela #define CABLE_VALID_CAPTURE (1 << SNDRV_PCM_STREAM_CAPTURE) 187597603d6SJaroslav Kysela #define CABLE_VALID_BOTH (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE) 188597603d6SJaroslav Kysela 189597603d6SJaroslav Kysela static int loopback_check_format(struct loopback_cable *cable, int stream) 190597603d6SJaroslav Kysela { 191b1c73fc8SJaroslav Kysela struct snd_pcm_runtime *runtime, *cruntime; 192597603d6SJaroslav Kysela struct loopback_setup *setup; 193597603d6SJaroslav Kysela struct snd_card *card; 194597603d6SJaroslav Kysela int check; 195597603d6SJaroslav Kysela 196597603d6SJaroslav Kysela if (cable->valid != CABLE_VALID_BOTH) { 197597603d6SJaroslav Kysela if (stream == SNDRV_PCM_STREAM_PLAYBACK) 198597603d6SJaroslav Kysela goto __notify; 199597603d6SJaroslav Kysela return 0; 200597603d6SJaroslav Kysela } 201597603d6SJaroslav Kysela runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> 202597603d6SJaroslav Kysela substream->runtime; 203b1c73fc8SJaroslav Kysela cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> 204b1c73fc8SJaroslav Kysela substream->runtime; 205b1c73fc8SJaroslav Kysela check = runtime->format != cruntime->format || 206b1c73fc8SJaroslav Kysela runtime->rate != cruntime->rate || 207b1c73fc8SJaroslav Kysela runtime->channels != cruntime->channels; 208597603d6SJaroslav Kysela if (!check) 209597603d6SJaroslav Kysela return 0; 210597603d6SJaroslav Kysela if (stream == SNDRV_PCM_STREAM_CAPTURE) { 211597603d6SJaroslav Kysela return -EIO; 212597603d6SJaroslav Kysela } else { 213597603d6SJaroslav Kysela snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> 214597603d6SJaroslav Kysela substream, SNDRV_PCM_STATE_DRAINING); 215597603d6SJaroslav Kysela __notify: 216597603d6SJaroslav Kysela runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> 217597603d6SJaroslav Kysela substream->runtime; 218597603d6SJaroslav Kysela setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]); 219597603d6SJaroslav Kysela card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card; 220597603d6SJaroslav Kysela if (setup->format != runtime->format) { 221597603d6SJaroslav Kysela snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, 222597603d6SJaroslav Kysela &setup->format_id); 223597603d6SJaroslav Kysela setup->format = runtime->format; 224597603d6SJaroslav Kysela } 225597603d6SJaroslav Kysela if (setup->rate != runtime->rate) { 226597603d6SJaroslav Kysela snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, 227597603d6SJaroslav Kysela &setup->rate_id); 228597603d6SJaroslav Kysela setup->rate = runtime->rate; 229597603d6SJaroslav Kysela } 230597603d6SJaroslav Kysela if (setup->channels != runtime->channels) { 231597603d6SJaroslav Kysela snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, 232597603d6SJaroslav Kysela &setup->channels_id); 233597603d6SJaroslav Kysela setup->channels = runtime->channels; 234597603d6SJaroslav Kysela } 235597603d6SJaroslav Kysela } 236597603d6SJaroslav Kysela return 0; 237597603d6SJaroslav Kysela } 238597603d6SJaroslav Kysela 239597603d6SJaroslav Kysela static void loopback_active_notify(struct loopback_pcm *dpcm) 240597603d6SJaroslav Kysela { 241597603d6SJaroslav Kysela snd_ctl_notify(dpcm->loopback->card, 242597603d6SJaroslav Kysela SNDRV_CTL_EVENT_MASK_VALUE, 243597603d6SJaroslav Kysela &get_setup(dpcm)->active_id); 244597603d6SJaroslav Kysela } 245597603d6SJaroslav Kysela 246597603d6SJaroslav Kysela static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) 247597603d6SJaroslav Kysela { 248597603d6SJaroslav Kysela struct snd_pcm_runtime *runtime = substream->runtime; 249597603d6SJaroslav Kysela struct loopback_pcm *dpcm = runtime->private_data; 250597603d6SJaroslav Kysela struct loopback_cable *cable = dpcm->cable; 251597603d6SJaroslav Kysela int err; 252597603d6SJaroslav Kysela 253597603d6SJaroslav Kysela switch (cmd) { 254597603d6SJaroslav Kysela case SNDRV_PCM_TRIGGER_START: 255597603d6SJaroslav Kysela err = loopback_check_format(cable, substream->stream); 256597603d6SJaroslav Kysela if (err < 0) 257597603d6SJaroslav Kysela return err; 258597603d6SJaroslav Kysela dpcm->last_jiffies = jiffies; 259597603d6SJaroslav Kysela dpcm->pcm_rate_shift = 0; 260597603d6SJaroslav Kysela loopback_timer_start(dpcm); 261597603d6SJaroslav Kysela cable->running |= (1 << substream->stream); 262597603d6SJaroslav Kysela if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 263597603d6SJaroslav Kysela loopback_active_notify(dpcm); 264597603d6SJaroslav Kysela break; 265597603d6SJaroslav Kysela case SNDRV_PCM_TRIGGER_STOP: 266597603d6SJaroslav Kysela cable->running &= ~(1 << substream->stream); 267597603d6SJaroslav Kysela loopback_timer_stop(dpcm); 268597603d6SJaroslav Kysela if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 269597603d6SJaroslav Kysela loopback_active_notify(dpcm); 270597603d6SJaroslav Kysela break; 271597603d6SJaroslav Kysela default: 272597603d6SJaroslav Kysela return -EINVAL; 273597603d6SJaroslav Kysela } 274597603d6SJaroslav Kysela return 0; 275597603d6SJaroslav Kysela } 276597603d6SJaroslav Kysela 277b1c73fc8SJaroslav Kysela static void params_change_substream(struct loopback_pcm *dpcm, 278b1c73fc8SJaroslav Kysela struct snd_pcm_runtime *runtime) 279b1c73fc8SJaroslav Kysela { 280b1c73fc8SJaroslav Kysela struct snd_pcm_runtime *dst_runtime; 281b1c73fc8SJaroslav Kysela 282b1c73fc8SJaroslav Kysela if (dpcm == NULL || dpcm->substream == NULL) 283b1c73fc8SJaroslav Kysela return; 284b1c73fc8SJaroslav Kysela dst_runtime = dpcm->substream->runtime; 285b1c73fc8SJaroslav Kysela if (dst_runtime == NULL) 286b1c73fc8SJaroslav Kysela return; 287b1c73fc8SJaroslav Kysela dst_runtime->hw = dpcm->cable->hw; 288b1c73fc8SJaroslav Kysela } 289b1c73fc8SJaroslav Kysela 290b1c73fc8SJaroslav Kysela static void params_change(struct snd_pcm_substream *substream) 291b1c73fc8SJaroslav Kysela { 292b1c73fc8SJaroslav Kysela struct snd_pcm_runtime *runtime = substream->runtime; 293b1c73fc8SJaroslav Kysela struct loopback_pcm *dpcm = runtime->private_data; 294b1c73fc8SJaroslav Kysela struct loopback_cable *cable = dpcm->cable; 295b1c73fc8SJaroslav Kysela 296b1c73fc8SJaroslav Kysela cable->hw.formats = (1ULL << runtime->format); 297b1c73fc8SJaroslav Kysela cable->hw.rate_min = runtime->rate; 298b1c73fc8SJaroslav Kysela cable->hw.rate_max = runtime->rate; 299b1c73fc8SJaroslav Kysela cable->hw.channels_min = runtime->channels; 300b1c73fc8SJaroslav Kysela cable->hw.channels_max = runtime->channels; 301b1c73fc8SJaroslav Kysela params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK], 302b1c73fc8SJaroslav Kysela runtime); 303b1c73fc8SJaroslav Kysela params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE], 304b1c73fc8SJaroslav Kysela runtime); 305b1c73fc8SJaroslav Kysela } 306b1c73fc8SJaroslav Kysela 307597603d6SJaroslav Kysela static int loopback_prepare(struct snd_pcm_substream *substream) 308597603d6SJaroslav Kysela { 309597603d6SJaroslav Kysela struct snd_pcm_runtime *runtime = substream->runtime; 310597603d6SJaroslav Kysela struct loopback_pcm *dpcm = runtime->private_data; 311597603d6SJaroslav Kysela struct loopback_cable *cable = dpcm->cable; 312b1c73fc8SJaroslav Kysela int bps, salign; 313597603d6SJaroslav Kysela 314597603d6SJaroslav Kysela salign = (snd_pcm_format_width(runtime->format) * 315597603d6SJaroslav Kysela runtime->channels) / 8; 316597603d6SJaroslav Kysela bps = salign * runtime->rate; 317597603d6SJaroslav Kysela if (bps <= 0 || salign <= 0) 318597603d6SJaroslav Kysela return -EINVAL; 319597603d6SJaroslav Kysela 320597603d6SJaroslav Kysela dpcm->buf_pos = 0; 321597603d6SJaroslav Kysela dpcm->pcm_buffer_size = frames_to_bytes(runtime, runtime->buffer_size); 322597603d6SJaroslav Kysela if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 323597603d6SJaroslav Kysela /* clear capture buffer */ 324597603d6SJaroslav Kysela dpcm->silent_size = dpcm->pcm_buffer_size; 325597603d6SJaroslav Kysela snd_pcm_format_set_silence(runtime->format, runtime->dma_area, 326597603d6SJaroslav Kysela runtime->buffer_size * runtime->channels); 327597603d6SJaroslav Kysela } 328597603d6SJaroslav Kysela 329597603d6SJaroslav Kysela dpcm->irq_pos = 0; 330597603d6SJaroslav Kysela dpcm->period_update_pending = 0; 331597603d6SJaroslav Kysela dpcm->pcm_bps = bps; 332597603d6SJaroslav Kysela dpcm->pcm_salign = salign; 333597603d6SJaroslav Kysela dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size); 334597603d6SJaroslav Kysela 335597603d6SJaroslav Kysela mutex_lock(&dpcm->loopback->cable_lock); 336b1c73fc8SJaroslav Kysela if (!(cable->valid & ~(1 << substream->stream)) || 337b1c73fc8SJaroslav Kysela (get_setup(dpcm)->notify && 338b1c73fc8SJaroslav Kysela substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) 339b1c73fc8SJaroslav Kysela params_change(substream); 340597603d6SJaroslav Kysela cable->valid |= 1 << substream->stream; 341597603d6SJaroslav Kysela mutex_unlock(&dpcm->loopback->cable_lock); 342597603d6SJaroslav Kysela 343597603d6SJaroslav Kysela return 0; 344597603d6SJaroslav Kysela } 345597603d6SJaroslav Kysela 346597603d6SJaroslav Kysela static void clear_capture_buf(struct loopback_pcm *dpcm, unsigned int bytes) 347597603d6SJaroslav Kysela { 348597603d6SJaroslav Kysela struct snd_pcm_runtime *runtime = dpcm->substream->runtime; 349597603d6SJaroslav Kysela char *dst = runtime->dma_area; 350597603d6SJaroslav Kysela unsigned int dst_off = dpcm->buf_pos; 351597603d6SJaroslav Kysela 352597603d6SJaroslav Kysela if (dpcm->silent_size >= dpcm->pcm_buffer_size) 353597603d6SJaroslav Kysela return; 354597603d6SJaroslav Kysela if (dpcm->silent_size + bytes > dpcm->pcm_buffer_size) 355597603d6SJaroslav Kysela bytes = dpcm->pcm_buffer_size - dpcm->silent_size; 356597603d6SJaroslav Kysela 357597603d6SJaroslav Kysela for (;;) { 358597603d6SJaroslav Kysela unsigned int size = bytes; 359597603d6SJaroslav Kysela if (dst_off + size > dpcm->pcm_buffer_size) 360597603d6SJaroslav Kysela size = dpcm->pcm_buffer_size - dst_off; 361597603d6SJaroslav Kysela snd_pcm_format_set_silence(runtime->format, dst + dst_off, 362597603d6SJaroslav Kysela bytes_to_frames(runtime, size) * 363597603d6SJaroslav Kysela runtime->channels); 364597603d6SJaroslav Kysela dpcm->silent_size += size; 365597603d6SJaroslav Kysela bytes -= size; 366597603d6SJaroslav Kysela if (!bytes) 367597603d6SJaroslav Kysela break; 368597603d6SJaroslav Kysela dst_off = 0; 369597603d6SJaroslav Kysela } 370597603d6SJaroslav Kysela } 371597603d6SJaroslav Kysela 372597603d6SJaroslav Kysela static void copy_play_buf(struct loopback_pcm *play, 373597603d6SJaroslav Kysela struct loopback_pcm *capt, 374597603d6SJaroslav Kysela unsigned int bytes) 375597603d6SJaroslav Kysela { 376597603d6SJaroslav Kysela struct snd_pcm_runtime *runtime = play->substream->runtime; 37720d9a26dSJaroslav Kysela char *src = runtime->dma_area; 378597603d6SJaroslav Kysela char *dst = capt->substream->runtime->dma_area; 379597603d6SJaroslav Kysela unsigned int src_off = play->buf_pos; 380597603d6SJaroslav Kysela unsigned int dst_off = capt->buf_pos; 381597603d6SJaroslav Kysela unsigned int clear_bytes = 0; 382597603d6SJaroslav Kysela 383597603d6SJaroslav Kysela /* check if playback is draining, trim the capture copy size 384597603d6SJaroslav Kysela * when our pointer is at the end of playback ring buffer */ 385597603d6SJaroslav Kysela if (runtime->status->state == SNDRV_PCM_STATE_DRAINING && 386597603d6SJaroslav Kysela snd_pcm_playback_hw_avail(runtime) < runtime->buffer_size) { 387597603d6SJaroslav Kysela snd_pcm_uframes_t appl_ptr, appl_ptr1, diff; 388597603d6SJaroslav Kysela appl_ptr = appl_ptr1 = runtime->control->appl_ptr; 389597603d6SJaroslav Kysela appl_ptr1 -= appl_ptr1 % runtime->buffer_size; 390597603d6SJaroslav Kysela appl_ptr1 += play->buf_pos / play->pcm_salign; 391597603d6SJaroslav Kysela if (appl_ptr < appl_ptr1) 392597603d6SJaroslav Kysela appl_ptr1 -= runtime->buffer_size; 393597603d6SJaroslav Kysela diff = (appl_ptr - appl_ptr1) * play->pcm_salign; 394597603d6SJaroslav Kysela if (diff < bytes) { 395597603d6SJaroslav Kysela clear_bytes = bytes - diff; 396597603d6SJaroslav Kysela bytes = diff; 397597603d6SJaroslav Kysela } 398597603d6SJaroslav Kysela } 399597603d6SJaroslav Kysela 400597603d6SJaroslav Kysela for (;;) { 401597603d6SJaroslav Kysela unsigned int size = bytes; 402597603d6SJaroslav Kysela if (src_off + size > play->pcm_buffer_size) 403597603d6SJaroslav Kysela size = play->pcm_buffer_size - src_off; 404597603d6SJaroslav Kysela if (dst_off + size > capt->pcm_buffer_size) 405597603d6SJaroslav Kysela size = capt->pcm_buffer_size - dst_off; 406597603d6SJaroslav Kysela memcpy(dst + dst_off, src + src_off, size); 407597603d6SJaroslav Kysela capt->silent_size = 0; 408597603d6SJaroslav Kysela bytes -= size; 409597603d6SJaroslav Kysela if (!bytes) 410597603d6SJaroslav Kysela break; 411597603d6SJaroslav Kysela src_off = (src_off + size) % play->pcm_buffer_size; 412597603d6SJaroslav Kysela dst_off = (dst_off + size) % capt->pcm_buffer_size; 413597603d6SJaroslav Kysela } 414597603d6SJaroslav Kysela 41520d9a26dSJaroslav Kysela if (clear_bytes > 0) { 416597603d6SJaroslav Kysela clear_capture_buf(capt, clear_bytes); 41720d9a26dSJaroslav Kysela capt->silent_size = 0; 41820d9a26dSJaroslav Kysela } 419597603d6SJaroslav Kysela } 420597603d6SJaroslav Kysela 421597603d6SJaroslav Kysela #define BYTEPOS_UPDATE_POSONLY 0 422597603d6SJaroslav Kysela #define BYTEPOS_UPDATE_CLEAR 1 423597603d6SJaroslav Kysela #define BYTEPOS_UPDATE_COPY 2 424597603d6SJaroslav Kysela 425597603d6SJaroslav Kysela static void loopback_bytepos_update(struct loopback_pcm *dpcm, 426597603d6SJaroslav Kysela unsigned int delta, 427597603d6SJaroslav Kysela unsigned int cmd) 428597603d6SJaroslav Kysela { 429597603d6SJaroslav Kysela unsigned int count; 430597603d6SJaroslav Kysela unsigned long last_pos; 431597603d6SJaroslav Kysela 432597603d6SJaroslav Kysela last_pos = byte_pos(dpcm, dpcm->irq_pos); 433597603d6SJaroslav Kysela dpcm->irq_pos += delta * dpcm->pcm_bps; 434597603d6SJaroslav Kysela count = byte_pos(dpcm, dpcm->irq_pos) - last_pos; 435597603d6SJaroslav Kysela if (!count) 436597603d6SJaroslav Kysela return; 437597603d6SJaroslav Kysela if (cmd == BYTEPOS_UPDATE_CLEAR) 438597603d6SJaroslav Kysela clear_capture_buf(dpcm, count); 439597603d6SJaroslav Kysela else if (cmd == BYTEPOS_UPDATE_COPY) 440597603d6SJaroslav Kysela copy_play_buf(dpcm->cable->streams[SNDRV_PCM_STREAM_PLAYBACK], 441597603d6SJaroslav Kysela dpcm->cable->streams[SNDRV_PCM_STREAM_CAPTURE], 442597603d6SJaroslav Kysela count); 443597603d6SJaroslav Kysela dpcm->buf_pos += count; 444597603d6SJaroslav Kysela dpcm->buf_pos %= dpcm->pcm_buffer_size; 445597603d6SJaroslav Kysela if (dpcm->irq_pos >= dpcm->period_size_frac) { 446597603d6SJaroslav Kysela dpcm->irq_pos %= dpcm->period_size_frac; 447597603d6SJaroslav Kysela dpcm->period_update_pending = 1; 448597603d6SJaroslav Kysela } 449597603d6SJaroslav Kysela } 450597603d6SJaroslav Kysela 451597603d6SJaroslav Kysela static void loopback_pos_update(struct loopback_cable *cable) 452597603d6SJaroslav Kysela { 453597603d6SJaroslav Kysela struct loopback_pcm *dpcm_play = 454597603d6SJaroslav Kysela cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; 455597603d6SJaroslav Kysela struct loopback_pcm *dpcm_capt = 456597603d6SJaroslav Kysela cable->streams[SNDRV_PCM_STREAM_CAPTURE]; 457597603d6SJaroslav Kysela unsigned long delta_play = 0, delta_capt = 0; 458597603d6SJaroslav Kysela 459597603d6SJaroslav Kysela spin_lock(&cable->lock); 460597603d6SJaroslav Kysela if (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { 461597603d6SJaroslav Kysela delta_play = jiffies - dpcm_play->last_jiffies; 462597603d6SJaroslav Kysela dpcm_play->last_jiffies += delta_play; 463597603d6SJaroslav Kysela } 464597603d6SJaroslav Kysela 465597603d6SJaroslav Kysela if (cable->running & (1 << SNDRV_PCM_STREAM_CAPTURE)) { 466597603d6SJaroslav Kysela delta_capt = jiffies - dpcm_capt->last_jiffies; 467597603d6SJaroslav Kysela dpcm_capt->last_jiffies += delta_capt; 468597603d6SJaroslav Kysela } 469597603d6SJaroslav Kysela 470597603d6SJaroslav Kysela if (delta_play == 0 && delta_capt == 0) { 471597603d6SJaroslav Kysela spin_unlock(&cable->lock); 472597603d6SJaroslav Kysela return; 473597603d6SJaroslav Kysela } 474597603d6SJaroslav Kysela 475597603d6SJaroslav Kysela if (delta_play > delta_capt) { 476597603d6SJaroslav Kysela loopback_bytepos_update(dpcm_play, delta_play - delta_capt, 477597603d6SJaroslav Kysela BYTEPOS_UPDATE_POSONLY); 478597603d6SJaroslav Kysela delta_play = delta_capt; 479597603d6SJaroslav Kysela } else if (delta_play < delta_capt) { 480597603d6SJaroslav Kysela loopback_bytepos_update(dpcm_capt, delta_capt - delta_play, 481597603d6SJaroslav Kysela BYTEPOS_UPDATE_CLEAR); 482597603d6SJaroslav Kysela delta_capt = delta_play; 483597603d6SJaroslav Kysela } 484597603d6SJaroslav Kysela 485597603d6SJaroslav Kysela if (delta_play == 0 && delta_capt == 0) { 486597603d6SJaroslav Kysela spin_unlock(&cable->lock); 487597603d6SJaroslav Kysela return; 488597603d6SJaroslav Kysela } 489597603d6SJaroslav Kysela /* note delta_capt == delta_play at this moment */ 490597603d6SJaroslav Kysela loopback_bytepos_update(dpcm_capt, delta_capt, BYTEPOS_UPDATE_COPY); 491597603d6SJaroslav Kysela loopback_bytepos_update(dpcm_play, delta_play, BYTEPOS_UPDATE_POSONLY); 492597603d6SJaroslav Kysela spin_unlock(&cable->lock); 493597603d6SJaroslav Kysela } 494597603d6SJaroslav Kysela 495597603d6SJaroslav Kysela static void loopback_timer_function(unsigned long data) 496597603d6SJaroslav Kysela { 497597603d6SJaroslav Kysela struct loopback_pcm *dpcm = (struct loopback_pcm *)data; 498597603d6SJaroslav Kysela int stream; 499597603d6SJaroslav Kysela 500597603d6SJaroslav Kysela loopback_pos_update(dpcm->cable); 501597603d6SJaroslav Kysela stream = dpcm->substream->stream; 502597603d6SJaroslav Kysela if (dpcm->cable->running & (1 << stream)) 503597603d6SJaroslav Kysela loopback_timer_start(dpcm); 504597603d6SJaroslav Kysela if (dpcm->period_update_pending) { 505597603d6SJaroslav Kysela dpcm->period_update_pending = 0; 506597603d6SJaroslav Kysela if (dpcm->cable->running & (1 << stream)) 507597603d6SJaroslav Kysela snd_pcm_period_elapsed(dpcm->substream); 508597603d6SJaroslav Kysela } 509597603d6SJaroslav Kysela } 510597603d6SJaroslav Kysela 511597603d6SJaroslav Kysela static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) 512597603d6SJaroslav Kysela { 513597603d6SJaroslav Kysela struct snd_pcm_runtime *runtime = substream->runtime; 514597603d6SJaroslav Kysela struct loopback_pcm *dpcm = runtime->private_data; 515597603d6SJaroslav Kysela 516597603d6SJaroslav Kysela loopback_pos_update(dpcm->cable); 517597603d6SJaroslav Kysela return bytes_to_frames(runtime, dpcm->buf_pos); 518597603d6SJaroslav Kysela } 519597603d6SJaroslav Kysela 520597603d6SJaroslav Kysela static struct snd_pcm_hardware loopback_pcm_hardware = 521597603d6SJaroslav Kysela { 522597603d6SJaroslav Kysela .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | 523597603d6SJaroslav Kysela SNDRV_PCM_INFO_MMAP_VALID), 524597603d6SJaroslav Kysela .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | 525597603d6SJaroslav Kysela SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | 526597603d6SJaroslav Kysela SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE), 527597603d6SJaroslav Kysela .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000, 528597603d6SJaroslav Kysela .rate_min = 8000, 529597603d6SJaroslav Kysela .rate_max = 192000, 530597603d6SJaroslav Kysela .channels_min = 1, 531597603d6SJaroslav Kysela .channels_max = 32, 532597603d6SJaroslav Kysela .buffer_bytes_max = 2 * 1024 * 1024, 533597603d6SJaroslav Kysela .period_bytes_min = 64, 534597603d6SJaroslav Kysela .period_bytes_max = 2 * 1024 * 1024, 535597603d6SJaroslav Kysela .periods_min = 1, 536597603d6SJaroslav Kysela .periods_max = 1024, 537597603d6SJaroslav Kysela .fifo_size = 0, 538597603d6SJaroslav Kysela }; 539597603d6SJaroslav Kysela 540597603d6SJaroslav Kysela static void loopback_runtime_free(struct snd_pcm_runtime *runtime) 541597603d6SJaroslav Kysela { 542597603d6SJaroslav Kysela struct loopback_pcm *dpcm = runtime->private_data; 543597603d6SJaroslav Kysela kfree(dpcm); 544597603d6SJaroslav Kysela } 545597603d6SJaroslav Kysela 546597603d6SJaroslav Kysela static int loopback_hw_params(struct snd_pcm_substream *substream, 547597603d6SJaroslav Kysela struct snd_pcm_hw_params *params) 548597603d6SJaroslav Kysela { 549597603d6SJaroslav Kysela return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); 550597603d6SJaroslav Kysela } 551597603d6SJaroslav Kysela 552597603d6SJaroslav Kysela static int loopback_hw_free(struct snd_pcm_substream *substream) 553597603d6SJaroslav Kysela { 554597603d6SJaroslav Kysela struct snd_pcm_runtime *runtime = substream->runtime; 555597603d6SJaroslav Kysela struct loopback_pcm *dpcm = runtime->private_data; 556597603d6SJaroslav Kysela struct loopback_cable *cable = dpcm->cable; 557597603d6SJaroslav Kysela 558597603d6SJaroslav Kysela mutex_lock(&dpcm->loopback->cable_lock); 559597603d6SJaroslav Kysela cable->valid &= ~(1 << substream->stream); 560597603d6SJaroslav Kysela mutex_unlock(&dpcm->loopback->cable_lock); 561597603d6SJaroslav Kysela return snd_pcm_lib_free_pages(substream); 562597603d6SJaroslav Kysela } 563597603d6SJaroslav Kysela 564597603d6SJaroslav Kysela static unsigned int get_cable_index(struct snd_pcm_substream *substream) 565597603d6SJaroslav Kysela { 566597603d6SJaroslav Kysela if (!substream->pcm->device) 567597603d6SJaroslav Kysela return substream->stream; 568597603d6SJaroslav Kysela else 569597603d6SJaroslav Kysela return !substream->stream; 570597603d6SJaroslav Kysela } 571597603d6SJaroslav Kysela 572b1c73fc8SJaroslav Kysela static int rule_format(struct snd_pcm_hw_params *params, 573b1c73fc8SJaroslav Kysela struct snd_pcm_hw_rule *rule) 574b1c73fc8SJaroslav Kysela { 575b1c73fc8SJaroslav Kysela 576b1c73fc8SJaroslav Kysela struct snd_pcm_hardware *hw = rule->private; 577b1c73fc8SJaroslav Kysela struct snd_mask *maskp = hw_param_mask(params, rule->var); 578b1c73fc8SJaroslav Kysela 579b1c73fc8SJaroslav Kysela maskp->bits[0] &= (u_int32_t)hw->formats; 580b1c73fc8SJaroslav Kysela maskp->bits[1] &= (u_int32_t)(hw->formats >> 32); 581b1c73fc8SJaroslav Kysela memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */ 582b1c73fc8SJaroslav Kysela if (! maskp->bits[0] && ! maskp->bits[1]) 583b1c73fc8SJaroslav Kysela return -EINVAL; 584b1c73fc8SJaroslav Kysela return 0; 585b1c73fc8SJaroslav Kysela } 586b1c73fc8SJaroslav Kysela 587b1c73fc8SJaroslav Kysela static int rule_rate(struct snd_pcm_hw_params *params, 588b1c73fc8SJaroslav Kysela struct snd_pcm_hw_rule *rule) 589b1c73fc8SJaroslav Kysela { 590b1c73fc8SJaroslav Kysela struct snd_pcm_hardware *hw = rule->private; 591b1c73fc8SJaroslav Kysela struct snd_interval t; 592b1c73fc8SJaroslav Kysela 593b1c73fc8SJaroslav Kysela t.min = hw->rate_min; 594b1c73fc8SJaroslav Kysela t.max = hw->rate_max; 595b1c73fc8SJaroslav Kysela t.openmin = t.openmax = 0; 596b1c73fc8SJaroslav Kysela t.integer = 0; 597b1c73fc8SJaroslav Kysela return snd_interval_refine(hw_param_interval(params, rule->var), &t); 598b1c73fc8SJaroslav Kysela } 599b1c73fc8SJaroslav Kysela 600b1c73fc8SJaroslav Kysela static int rule_channels(struct snd_pcm_hw_params *params, 601b1c73fc8SJaroslav Kysela struct snd_pcm_hw_rule *rule) 602b1c73fc8SJaroslav Kysela { 603b1c73fc8SJaroslav Kysela struct snd_pcm_hardware *hw = rule->private; 604b1c73fc8SJaroslav Kysela struct snd_interval t; 605b1c73fc8SJaroslav Kysela 606b1c73fc8SJaroslav Kysela t.min = hw->channels_min; 607b1c73fc8SJaroslav Kysela t.max = hw->channels_max; 608b1c73fc8SJaroslav Kysela t.openmin = t.openmax = 0; 609b1c73fc8SJaroslav Kysela t.integer = 0; 610b1c73fc8SJaroslav Kysela return snd_interval_refine(hw_param_interval(params, rule->var), &t); 611b1c73fc8SJaroslav Kysela } 612b1c73fc8SJaroslav Kysela 613597603d6SJaroslav Kysela static int loopback_open(struct snd_pcm_substream *substream) 614597603d6SJaroslav Kysela { 615597603d6SJaroslav Kysela struct snd_pcm_runtime *runtime = substream->runtime; 616597603d6SJaroslav Kysela struct loopback *loopback = substream->private_data; 617597603d6SJaroslav Kysela struct loopback_pcm *dpcm; 618597603d6SJaroslav Kysela struct loopback_cable *cable; 619597603d6SJaroslav Kysela int err = 0; 620597603d6SJaroslav Kysela int dev = get_cable_index(substream); 621597603d6SJaroslav Kysela 622597603d6SJaroslav Kysela mutex_lock(&loopback->cable_lock); 623597603d6SJaroslav Kysela dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); 624597603d6SJaroslav Kysela if (!dpcm) { 625597603d6SJaroslav Kysela err = -ENOMEM; 626597603d6SJaroslav Kysela goto unlock; 627597603d6SJaroslav Kysela } 628597603d6SJaroslav Kysela dpcm->loopback = loopback; 629597603d6SJaroslav Kysela dpcm->substream = substream; 630597603d6SJaroslav Kysela setup_timer(&dpcm->timer, loopback_timer_function, 631597603d6SJaroslav Kysela (unsigned long)dpcm); 632597603d6SJaroslav Kysela 633597603d6SJaroslav Kysela cable = loopback->cables[substream->number][dev]; 634597603d6SJaroslav Kysela if (!cable) { 635597603d6SJaroslav Kysela cable = kzalloc(sizeof(*cable), GFP_KERNEL); 636597603d6SJaroslav Kysela if (!cable) { 637597603d6SJaroslav Kysela kfree(dpcm); 638597603d6SJaroslav Kysela err = -ENOMEM; 639597603d6SJaroslav Kysela goto unlock; 640597603d6SJaroslav Kysela } 641597603d6SJaroslav Kysela spin_lock_init(&cable->lock); 642597603d6SJaroslav Kysela cable->hw = loopback_pcm_hardware; 643597603d6SJaroslav Kysela loopback->cables[substream->number][dev] = cable; 644597603d6SJaroslav Kysela } 645597603d6SJaroslav Kysela dpcm->cable = cable; 646597603d6SJaroslav Kysela cable->streams[substream->stream] = dpcm; 647597603d6SJaroslav Kysela 648597603d6SJaroslav Kysela snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 649597603d6SJaroslav Kysela 650b1c73fc8SJaroslav Kysela /* use dynamic rules based on actual runtime->hw values */ 651b1c73fc8SJaroslav Kysela /* note that the default rules created in the PCM midlevel code */ 652b1c73fc8SJaroslav Kysela /* are cached -> they do not reflect the actual state */ 653b1c73fc8SJaroslav Kysela err = snd_pcm_hw_rule_add(runtime, 0, 654b1c73fc8SJaroslav Kysela SNDRV_PCM_HW_PARAM_FORMAT, 655b1c73fc8SJaroslav Kysela rule_format, &runtime->hw, 656b1c73fc8SJaroslav Kysela SNDRV_PCM_HW_PARAM_FORMAT, -1); 657b1c73fc8SJaroslav Kysela if (err < 0) 658b1c73fc8SJaroslav Kysela goto unlock; 659b1c73fc8SJaroslav Kysela err = snd_pcm_hw_rule_add(runtime, 0, 660b1c73fc8SJaroslav Kysela SNDRV_PCM_HW_PARAM_RATE, 661b1c73fc8SJaroslav Kysela rule_rate, &runtime->hw, 662b1c73fc8SJaroslav Kysela SNDRV_PCM_HW_PARAM_RATE, -1); 663b1c73fc8SJaroslav Kysela if (err < 0) 664b1c73fc8SJaroslav Kysela goto unlock; 665b1c73fc8SJaroslav Kysela err = snd_pcm_hw_rule_add(runtime, 0, 666b1c73fc8SJaroslav Kysela SNDRV_PCM_HW_PARAM_CHANNELS, 667b1c73fc8SJaroslav Kysela rule_channels, &runtime->hw, 668b1c73fc8SJaroslav Kysela SNDRV_PCM_HW_PARAM_CHANNELS, -1); 669b1c73fc8SJaroslav Kysela if (err < 0) 670b1c73fc8SJaroslav Kysela goto unlock; 671b1c73fc8SJaroslav Kysela 672597603d6SJaroslav Kysela runtime->private_data = dpcm; 673597603d6SJaroslav Kysela runtime->private_free = loopback_runtime_free; 674b1c73fc8SJaroslav Kysela if (get_notify(dpcm)) 675597603d6SJaroslav Kysela runtime->hw = loopback_pcm_hardware; 676b1c73fc8SJaroslav Kysela else 677597603d6SJaroslav Kysela runtime->hw = cable->hw; 678597603d6SJaroslav Kysela unlock: 679597603d6SJaroslav Kysela mutex_unlock(&loopback->cable_lock); 680597603d6SJaroslav Kysela return err; 681597603d6SJaroslav Kysela } 682597603d6SJaroslav Kysela 683597603d6SJaroslav Kysela static int loopback_close(struct snd_pcm_substream *substream) 684597603d6SJaroslav Kysela { 685597603d6SJaroslav Kysela struct loopback *loopback = substream->private_data; 686597603d6SJaroslav Kysela struct loopback_pcm *dpcm = substream->runtime->private_data; 687597603d6SJaroslav Kysela struct loopback_cable *cable; 688597603d6SJaroslav Kysela int dev = get_cable_index(substream); 689597603d6SJaroslav Kysela 690597603d6SJaroslav Kysela loopback_timer_stop(dpcm); 691597603d6SJaroslav Kysela mutex_lock(&loopback->cable_lock); 692597603d6SJaroslav Kysela cable = loopback->cables[substream->number][dev]; 693597603d6SJaroslav Kysela if (cable->streams[!substream->stream]) { 694597603d6SJaroslav Kysela /* other stream is still alive */ 695597603d6SJaroslav Kysela cable->streams[substream->stream] = NULL; 696597603d6SJaroslav Kysela } else { 697597603d6SJaroslav Kysela /* free the cable */ 698597603d6SJaroslav Kysela loopback->cables[substream->number][dev] = NULL; 699597603d6SJaroslav Kysela kfree(cable); 700597603d6SJaroslav Kysela } 701597603d6SJaroslav Kysela mutex_unlock(&loopback->cable_lock); 702597603d6SJaroslav Kysela return 0; 703597603d6SJaroslav Kysela } 704597603d6SJaroslav Kysela 705597603d6SJaroslav Kysela static struct snd_pcm_ops loopback_playback_ops = { 706597603d6SJaroslav Kysela .open = loopback_open, 707597603d6SJaroslav Kysela .close = loopback_close, 708597603d6SJaroslav Kysela .ioctl = snd_pcm_lib_ioctl, 709597603d6SJaroslav Kysela .hw_params = loopback_hw_params, 710597603d6SJaroslav Kysela .hw_free = loopback_hw_free, 711597603d6SJaroslav Kysela .prepare = loopback_prepare, 712597603d6SJaroslav Kysela .trigger = loopback_trigger, 713597603d6SJaroslav Kysela .pointer = loopback_pointer, 714597603d6SJaroslav Kysela }; 715597603d6SJaroslav Kysela 716597603d6SJaroslav Kysela static struct snd_pcm_ops loopback_capture_ops = { 717597603d6SJaroslav Kysela .open = loopback_open, 718597603d6SJaroslav Kysela .close = loopback_close, 719597603d6SJaroslav Kysela .ioctl = snd_pcm_lib_ioctl, 720597603d6SJaroslav Kysela .hw_params = loopback_hw_params, 721597603d6SJaroslav Kysela .hw_free = loopback_hw_free, 722597603d6SJaroslav Kysela .prepare = loopback_prepare, 723597603d6SJaroslav Kysela .trigger = loopback_trigger, 724597603d6SJaroslav Kysela .pointer = loopback_pointer, 725597603d6SJaroslav Kysela }; 726597603d6SJaroslav Kysela 727597603d6SJaroslav Kysela static int __devinit loopback_pcm_new(struct loopback *loopback, 728597603d6SJaroslav Kysela int device, int substreams) 729597603d6SJaroslav Kysela { 730597603d6SJaroslav Kysela struct snd_pcm *pcm; 731597603d6SJaroslav Kysela int err; 732597603d6SJaroslav Kysela 733597603d6SJaroslav Kysela err = snd_pcm_new(loopback->card, "Loopback PCM", device, 734597603d6SJaroslav Kysela substreams, substreams, &pcm); 735597603d6SJaroslav Kysela if (err < 0) 736597603d6SJaroslav Kysela return err; 737597603d6SJaroslav Kysela snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_playback_ops); 738597603d6SJaroslav Kysela snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_capture_ops); 739597603d6SJaroslav Kysela 740597603d6SJaroslav Kysela pcm->private_data = loopback; 741597603d6SJaroslav Kysela pcm->info_flags = 0; 742597603d6SJaroslav Kysela strcpy(pcm->name, "Loopback PCM"); 743597603d6SJaroslav Kysela 744597603d6SJaroslav Kysela loopback->pcm[device] = pcm; 745597603d6SJaroslav Kysela 746597603d6SJaroslav Kysela snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, 747597603d6SJaroslav Kysela snd_dma_continuous_data(GFP_KERNEL), 748597603d6SJaroslav Kysela 0, 2 * 1024 * 1024); 749597603d6SJaroslav Kysela return 0; 750597603d6SJaroslav Kysela } 751597603d6SJaroslav Kysela 752597603d6SJaroslav Kysela static int loopback_rate_shift_info(struct snd_kcontrol *kcontrol, 753597603d6SJaroslav Kysela struct snd_ctl_elem_info *uinfo) 754597603d6SJaroslav Kysela { 755597603d6SJaroslav Kysela uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 756597603d6SJaroslav Kysela uinfo->count = 1; 757597603d6SJaroslav Kysela uinfo->value.integer.min = 80000; 758597603d6SJaroslav Kysela uinfo->value.integer.max = 120000; 759597603d6SJaroslav Kysela uinfo->value.integer.step = 1; 760597603d6SJaroslav Kysela return 0; 761597603d6SJaroslav Kysela } 762597603d6SJaroslav Kysela 763597603d6SJaroslav Kysela static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol, 764597603d6SJaroslav Kysela struct snd_ctl_elem_value *ucontrol) 765597603d6SJaroslav Kysela { 766597603d6SJaroslav Kysela struct loopback *loopback = snd_kcontrol_chip(kcontrol); 767597603d6SJaroslav Kysela 768597603d6SJaroslav Kysela ucontrol->value.integer.value[0] = 769597603d6SJaroslav Kysela loopback->setup[kcontrol->id.subdevice] 770597603d6SJaroslav Kysela [kcontrol->id.device].rate_shift; 771597603d6SJaroslav Kysela return 0; 772597603d6SJaroslav Kysela } 773597603d6SJaroslav Kysela 774597603d6SJaroslav Kysela static int loopback_rate_shift_put(struct snd_kcontrol *kcontrol, 775597603d6SJaroslav Kysela struct snd_ctl_elem_value *ucontrol) 776597603d6SJaroslav Kysela { 777597603d6SJaroslav Kysela struct loopback *loopback = snd_kcontrol_chip(kcontrol); 778597603d6SJaroslav Kysela unsigned int val; 779597603d6SJaroslav Kysela int change = 0; 780597603d6SJaroslav Kysela 781597603d6SJaroslav Kysela val = ucontrol->value.integer.value[0]; 782597603d6SJaroslav Kysela if (val < 80000) 783597603d6SJaroslav Kysela val = 80000; 784597603d6SJaroslav Kysela if (val > 120000) 785597603d6SJaroslav Kysela val = 120000; 786597603d6SJaroslav Kysela mutex_lock(&loopback->cable_lock); 787597603d6SJaroslav Kysela if (val != loopback->setup[kcontrol->id.subdevice] 788597603d6SJaroslav Kysela [kcontrol->id.device].rate_shift) { 789597603d6SJaroslav Kysela loopback->setup[kcontrol->id.subdevice] 790597603d6SJaroslav Kysela [kcontrol->id.device].rate_shift = val; 791597603d6SJaroslav Kysela change = 1; 792597603d6SJaroslav Kysela } 793597603d6SJaroslav Kysela mutex_unlock(&loopback->cable_lock); 794597603d6SJaroslav Kysela return change; 795597603d6SJaroslav Kysela } 796597603d6SJaroslav Kysela 797597603d6SJaroslav Kysela static int loopback_notify_get(struct snd_kcontrol *kcontrol, 798597603d6SJaroslav Kysela struct snd_ctl_elem_value *ucontrol) 799597603d6SJaroslav Kysela { 800597603d6SJaroslav Kysela struct loopback *loopback = snd_kcontrol_chip(kcontrol); 801597603d6SJaroslav Kysela 802597603d6SJaroslav Kysela ucontrol->value.integer.value[0] = 803597603d6SJaroslav Kysela loopback->setup[kcontrol->id.subdevice] 804597603d6SJaroslav Kysela [kcontrol->id.device].notify; 805597603d6SJaroslav Kysela return 0; 806597603d6SJaroslav Kysela } 807597603d6SJaroslav Kysela 808597603d6SJaroslav Kysela static int loopback_notify_put(struct snd_kcontrol *kcontrol, 809597603d6SJaroslav Kysela struct snd_ctl_elem_value *ucontrol) 810597603d6SJaroslav Kysela { 811597603d6SJaroslav Kysela struct loopback *loopback = snd_kcontrol_chip(kcontrol); 812597603d6SJaroslav Kysela unsigned int val; 813597603d6SJaroslav Kysela int change = 0; 814597603d6SJaroslav Kysela 815597603d6SJaroslav Kysela val = ucontrol->value.integer.value[0] ? 1 : 0; 816597603d6SJaroslav Kysela if (val != loopback->setup[kcontrol->id.subdevice] 817597603d6SJaroslav Kysela [kcontrol->id.device].notify) { 818597603d6SJaroslav Kysela loopback->setup[kcontrol->id.subdevice] 819597603d6SJaroslav Kysela [kcontrol->id.device].notify = val; 820597603d6SJaroslav Kysela change = 1; 821597603d6SJaroslav Kysela } 822597603d6SJaroslav Kysela return change; 823597603d6SJaroslav Kysela } 824597603d6SJaroslav Kysela 825597603d6SJaroslav Kysela static int loopback_active_get(struct snd_kcontrol *kcontrol, 826597603d6SJaroslav Kysela struct snd_ctl_elem_value *ucontrol) 827597603d6SJaroslav Kysela { 828597603d6SJaroslav Kysela struct loopback *loopback = snd_kcontrol_chip(kcontrol); 829597603d6SJaroslav Kysela struct loopback_cable *cable = loopback->cables 830ac446fb7SJaroslav Kysela [kcontrol->id.subdevice][kcontrol->id.device ^ 1]; 831597603d6SJaroslav Kysela unsigned int val = 0; 832597603d6SJaroslav Kysela 833597603d6SJaroslav Kysela if (cable != NULL) 834597603d6SJaroslav Kysela val = (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? 835597603d6SJaroslav Kysela 1 : 0; 836597603d6SJaroslav Kysela ucontrol->value.integer.value[0] = val; 837597603d6SJaroslav Kysela return 0; 838597603d6SJaroslav Kysela } 839597603d6SJaroslav Kysela 840597603d6SJaroslav Kysela static int loopback_format_info(struct snd_kcontrol *kcontrol, 841597603d6SJaroslav Kysela struct snd_ctl_elem_info *uinfo) 842597603d6SJaroslav Kysela { 843597603d6SJaroslav Kysela uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 844597603d6SJaroslav Kysela uinfo->count = 1; 845597603d6SJaroslav Kysela uinfo->value.integer.min = 0; 846597603d6SJaroslav Kysela uinfo->value.integer.max = SNDRV_PCM_FORMAT_LAST; 847597603d6SJaroslav Kysela uinfo->value.integer.step = 1; 848597603d6SJaroslav Kysela return 0; 849597603d6SJaroslav Kysela } 850597603d6SJaroslav Kysela 851597603d6SJaroslav Kysela static int loopback_format_get(struct snd_kcontrol *kcontrol, 852597603d6SJaroslav Kysela struct snd_ctl_elem_value *ucontrol) 853597603d6SJaroslav Kysela { 854597603d6SJaroslav Kysela struct loopback *loopback = snd_kcontrol_chip(kcontrol); 855597603d6SJaroslav Kysela 856597603d6SJaroslav Kysela ucontrol->value.integer.value[0] = 857597603d6SJaroslav Kysela loopback->setup[kcontrol->id.subdevice] 858597603d6SJaroslav Kysela [kcontrol->id.device].format; 859597603d6SJaroslav Kysela return 0; 860597603d6SJaroslav Kysela } 861597603d6SJaroslav Kysela 862597603d6SJaroslav Kysela static int loopback_rate_info(struct snd_kcontrol *kcontrol, 863597603d6SJaroslav Kysela struct snd_ctl_elem_info *uinfo) 864597603d6SJaroslav Kysela { 865597603d6SJaroslav Kysela uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 866597603d6SJaroslav Kysela uinfo->count = 1; 867597603d6SJaroslav Kysela uinfo->value.integer.min = 0; 868597603d6SJaroslav Kysela uinfo->value.integer.max = 192000; 869597603d6SJaroslav Kysela uinfo->value.integer.step = 1; 870597603d6SJaroslav Kysela return 0; 871597603d6SJaroslav Kysela } 872597603d6SJaroslav Kysela 873597603d6SJaroslav Kysela static int loopback_rate_get(struct snd_kcontrol *kcontrol, 874597603d6SJaroslav Kysela struct snd_ctl_elem_value *ucontrol) 875597603d6SJaroslav Kysela { 876597603d6SJaroslav Kysela struct loopback *loopback = snd_kcontrol_chip(kcontrol); 877597603d6SJaroslav Kysela 878597603d6SJaroslav Kysela ucontrol->value.integer.value[0] = 879597603d6SJaroslav Kysela loopback->setup[kcontrol->id.subdevice] 880597603d6SJaroslav Kysela [kcontrol->id.device].rate; 881597603d6SJaroslav Kysela return 0; 882597603d6SJaroslav Kysela } 883597603d6SJaroslav Kysela 884597603d6SJaroslav Kysela static int loopback_channels_info(struct snd_kcontrol *kcontrol, 885597603d6SJaroslav Kysela struct snd_ctl_elem_info *uinfo) 886597603d6SJaroslav Kysela { 887597603d6SJaroslav Kysela uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 888597603d6SJaroslav Kysela uinfo->count = 1; 889597603d6SJaroslav Kysela uinfo->value.integer.min = 1; 890597603d6SJaroslav Kysela uinfo->value.integer.max = 1024; 891597603d6SJaroslav Kysela uinfo->value.integer.step = 1; 892597603d6SJaroslav Kysela return 0; 893597603d6SJaroslav Kysela } 894597603d6SJaroslav Kysela 895597603d6SJaroslav Kysela static int loopback_channels_get(struct snd_kcontrol *kcontrol, 896597603d6SJaroslav Kysela struct snd_ctl_elem_value *ucontrol) 897597603d6SJaroslav Kysela { 898597603d6SJaroslav Kysela struct loopback *loopback = snd_kcontrol_chip(kcontrol); 899597603d6SJaroslav Kysela 900597603d6SJaroslav Kysela ucontrol->value.integer.value[0] = 901597603d6SJaroslav Kysela loopback->setup[kcontrol->id.subdevice] 9021446c5fbSJaroslav Kysela [kcontrol->id.device].channels; 903597603d6SJaroslav Kysela return 0; 904597603d6SJaroslav Kysela } 905597603d6SJaroslav Kysela 906597603d6SJaroslav Kysela static struct snd_kcontrol_new loopback_controls[] __devinitdata = { 907597603d6SJaroslav Kysela { 908597603d6SJaroslav Kysela .iface = SNDRV_CTL_ELEM_IFACE_PCM, 909597603d6SJaroslav Kysela .name = "PCM Rate Shift 100000", 910597603d6SJaroslav Kysela .info = loopback_rate_shift_info, 911597603d6SJaroslav Kysela .get = loopback_rate_shift_get, 912597603d6SJaroslav Kysela .put = loopback_rate_shift_put, 913597603d6SJaroslav Kysela }, 914597603d6SJaroslav Kysela { 915597603d6SJaroslav Kysela .iface = SNDRV_CTL_ELEM_IFACE_PCM, 916597603d6SJaroslav Kysela .name = "PCM Notify", 917597603d6SJaroslav Kysela .info = snd_ctl_boolean_mono_info, 918597603d6SJaroslav Kysela .get = loopback_notify_get, 919597603d6SJaroslav Kysela .put = loopback_notify_put, 920597603d6SJaroslav Kysela }, 921597603d6SJaroslav Kysela #define ACTIVE_IDX 2 922597603d6SJaroslav Kysela { 923597603d6SJaroslav Kysela .access = SNDRV_CTL_ELEM_ACCESS_READ, 924597603d6SJaroslav Kysela .iface = SNDRV_CTL_ELEM_IFACE_PCM, 925597603d6SJaroslav Kysela .name = "PCM Slave Active", 926597603d6SJaroslav Kysela .info = snd_ctl_boolean_mono_info, 927597603d6SJaroslav Kysela .get = loopback_active_get, 928597603d6SJaroslav Kysela }, 929597603d6SJaroslav Kysela #define FORMAT_IDX 3 930597603d6SJaroslav Kysela { 931597603d6SJaroslav Kysela .access = SNDRV_CTL_ELEM_ACCESS_READ, 932597603d6SJaroslav Kysela .iface = SNDRV_CTL_ELEM_IFACE_PCM, 933597603d6SJaroslav Kysela .name = "PCM Slave Format", 934597603d6SJaroslav Kysela .info = loopback_format_info, 935597603d6SJaroslav Kysela .get = loopback_format_get 936597603d6SJaroslav Kysela }, 937597603d6SJaroslav Kysela #define RATE_IDX 4 938597603d6SJaroslav Kysela { 939597603d6SJaroslav Kysela .access = SNDRV_CTL_ELEM_ACCESS_READ, 940597603d6SJaroslav Kysela .iface = SNDRV_CTL_ELEM_IFACE_PCM, 941597603d6SJaroslav Kysela .name = "PCM Slave Rate", 942597603d6SJaroslav Kysela .info = loopback_rate_info, 943597603d6SJaroslav Kysela .get = loopback_rate_get 944597603d6SJaroslav Kysela }, 945597603d6SJaroslav Kysela #define CHANNELS_IDX 5 946597603d6SJaroslav Kysela { 947597603d6SJaroslav Kysela .access = SNDRV_CTL_ELEM_ACCESS_READ, 948597603d6SJaroslav Kysela .iface = SNDRV_CTL_ELEM_IFACE_PCM, 949597603d6SJaroslav Kysela .name = "PCM Slave Channels", 950597603d6SJaroslav Kysela .info = loopback_channels_info, 951597603d6SJaroslav Kysela .get = loopback_channels_get 952597603d6SJaroslav Kysela } 953597603d6SJaroslav Kysela }; 954597603d6SJaroslav Kysela 955597603d6SJaroslav Kysela static int __devinit loopback_mixer_new(struct loopback *loopback, int notify) 956597603d6SJaroslav Kysela { 957597603d6SJaroslav Kysela struct snd_card *card = loopback->card; 958597603d6SJaroslav Kysela struct snd_pcm *pcm; 959597603d6SJaroslav Kysela struct snd_kcontrol *kctl; 960597603d6SJaroslav Kysela struct loopback_setup *setup; 961597603d6SJaroslav Kysela int err, dev, substr, substr_count, idx; 962597603d6SJaroslav Kysela 963597603d6SJaroslav Kysela strcpy(card->mixername, "Loopback Mixer"); 964597603d6SJaroslav Kysela for (dev = 0; dev < 2; dev++) { 965597603d6SJaroslav Kysela pcm = loopback->pcm[dev]; 966597603d6SJaroslav Kysela substr_count = 967597603d6SJaroslav Kysela pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count; 968597603d6SJaroslav Kysela for (substr = 0; substr < substr_count; substr++) { 969597603d6SJaroslav Kysela setup = &loopback->setup[substr][dev]; 970597603d6SJaroslav Kysela setup->notify = notify; 971597603d6SJaroslav Kysela setup->rate_shift = NO_PITCH; 972597603d6SJaroslav Kysela setup->format = SNDRV_PCM_FORMAT_S16_LE; 973597603d6SJaroslav Kysela setup->rate = 48000; 974597603d6SJaroslav Kysela setup->channels = 2; 975597603d6SJaroslav Kysela for (idx = 0; idx < ARRAY_SIZE(loopback_controls); 976597603d6SJaroslav Kysela idx++) { 977597603d6SJaroslav Kysela kctl = snd_ctl_new1(&loopback_controls[idx], 978597603d6SJaroslav Kysela loopback); 979597603d6SJaroslav Kysela if (!kctl) 980597603d6SJaroslav Kysela return -ENOMEM; 981597603d6SJaroslav Kysela kctl->id.device = dev; 982597603d6SJaroslav Kysela kctl->id.subdevice = substr; 983597603d6SJaroslav Kysela switch (idx) { 984597603d6SJaroslav Kysela case ACTIVE_IDX: 985597603d6SJaroslav Kysela setup->active_id = kctl->id; 986597603d6SJaroslav Kysela break; 987597603d6SJaroslav Kysela case FORMAT_IDX: 988597603d6SJaroslav Kysela setup->format_id = kctl->id; 989597603d6SJaroslav Kysela break; 990597603d6SJaroslav Kysela case RATE_IDX: 991597603d6SJaroslav Kysela setup->rate_id = kctl->id; 992597603d6SJaroslav Kysela break; 993597603d6SJaroslav Kysela case CHANNELS_IDX: 994597603d6SJaroslav Kysela setup->channels_id = kctl->id; 995597603d6SJaroslav Kysela break; 996597603d6SJaroslav Kysela default: 997597603d6SJaroslav Kysela break; 998597603d6SJaroslav Kysela } 999597603d6SJaroslav Kysela err = snd_ctl_add(card, kctl); 1000597603d6SJaroslav Kysela if (err < 0) 1001597603d6SJaroslav Kysela return err; 1002597603d6SJaroslav Kysela } 1003597603d6SJaroslav Kysela } 1004597603d6SJaroslav Kysela } 1005597603d6SJaroslav Kysela return 0; 1006597603d6SJaroslav Kysela } 1007597603d6SJaroslav Kysela 1008597603d6SJaroslav Kysela static int __devinit loopback_probe(struct platform_device *devptr) 1009597603d6SJaroslav Kysela { 1010597603d6SJaroslav Kysela struct snd_card *card; 1011597603d6SJaroslav Kysela struct loopback *loopback; 1012597603d6SJaroslav Kysela int dev = devptr->id; 1013597603d6SJaroslav Kysela int err; 1014597603d6SJaroslav Kysela 1015597603d6SJaroslav Kysela err = snd_card_create(index[dev], id[dev], THIS_MODULE, 1016597603d6SJaroslav Kysela sizeof(struct loopback), &card); 1017597603d6SJaroslav Kysela if (err < 0) 1018597603d6SJaroslav Kysela return err; 1019597603d6SJaroslav Kysela loopback = card->private_data; 1020597603d6SJaroslav Kysela 1021597603d6SJaroslav Kysela if (pcm_substreams[dev] < 1) 1022597603d6SJaroslav Kysela pcm_substreams[dev] = 1; 1023597603d6SJaroslav Kysela if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS) 1024597603d6SJaroslav Kysela pcm_substreams[dev] = MAX_PCM_SUBSTREAMS; 1025597603d6SJaroslav Kysela 1026597603d6SJaroslav Kysela loopback->card = card; 1027597603d6SJaroslav Kysela mutex_init(&loopback->cable_lock); 1028597603d6SJaroslav Kysela 1029597603d6SJaroslav Kysela err = loopback_pcm_new(loopback, 0, pcm_substreams[dev]); 1030597603d6SJaroslav Kysela if (err < 0) 1031597603d6SJaroslav Kysela goto __nodev; 1032597603d6SJaroslav Kysela err = loopback_pcm_new(loopback, 1, pcm_substreams[dev]); 1033597603d6SJaroslav Kysela if (err < 0) 1034597603d6SJaroslav Kysela goto __nodev; 1035597603d6SJaroslav Kysela err = loopback_mixer_new(loopback, pcm_notify[dev] ? 1 : 0); 1036597603d6SJaroslav Kysela if (err < 0) 1037597603d6SJaroslav Kysela goto __nodev; 1038597603d6SJaroslav Kysela strcpy(card->driver, "Loopback"); 1039597603d6SJaroslav Kysela strcpy(card->shortname, "Loopback"); 1040597603d6SJaroslav Kysela sprintf(card->longname, "Loopback %i", dev + 1); 1041597603d6SJaroslav Kysela err = snd_card_register(card); 1042597603d6SJaroslav Kysela if (!err) { 1043597603d6SJaroslav Kysela platform_set_drvdata(devptr, card); 1044597603d6SJaroslav Kysela return 0; 1045597603d6SJaroslav Kysela } 1046597603d6SJaroslav Kysela __nodev: 1047597603d6SJaroslav Kysela snd_card_free(card); 1048597603d6SJaroslav Kysela return err; 1049597603d6SJaroslav Kysela } 1050597603d6SJaroslav Kysela 1051597603d6SJaroslav Kysela static int __devexit loopback_remove(struct platform_device *devptr) 1052597603d6SJaroslav Kysela { 1053597603d6SJaroslav Kysela snd_card_free(platform_get_drvdata(devptr)); 1054597603d6SJaroslav Kysela platform_set_drvdata(devptr, NULL); 1055597603d6SJaroslav Kysela return 0; 1056597603d6SJaroslav Kysela } 1057597603d6SJaroslav Kysela 1058597603d6SJaroslav Kysela #ifdef CONFIG_PM 1059597603d6SJaroslav Kysela static int loopback_suspend(struct platform_device *pdev, 1060597603d6SJaroslav Kysela pm_message_t state) 1061597603d6SJaroslav Kysela { 1062597603d6SJaroslav Kysela struct snd_card *card = platform_get_drvdata(pdev); 1063597603d6SJaroslav Kysela struct loopback *loopback = card->private_data; 1064597603d6SJaroslav Kysela 1065597603d6SJaroslav Kysela snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 1066597603d6SJaroslav Kysela 1067597603d6SJaroslav Kysela snd_pcm_suspend_all(loopback->pcm[0]); 1068597603d6SJaroslav Kysela snd_pcm_suspend_all(loopback->pcm[1]); 1069597603d6SJaroslav Kysela return 0; 1070597603d6SJaroslav Kysela } 1071597603d6SJaroslav Kysela 1072597603d6SJaroslav Kysela static int loopback_resume(struct platform_device *pdev) 1073597603d6SJaroslav Kysela { 1074597603d6SJaroslav Kysela struct snd_card *card = platform_get_drvdata(pdev); 1075597603d6SJaroslav Kysela 1076597603d6SJaroslav Kysela snd_power_change_state(card, SNDRV_CTL_POWER_D0); 1077597603d6SJaroslav Kysela return 0; 1078597603d6SJaroslav Kysela } 1079597603d6SJaroslav Kysela #endif 1080597603d6SJaroslav Kysela 1081597603d6SJaroslav Kysela #define SND_LOOPBACK_DRIVER "snd_aloop" 1082597603d6SJaroslav Kysela 1083597603d6SJaroslav Kysela static struct platform_driver loopback_driver = { 1084597603d6SJaroslav Kysela .probe = loopback_probe, 1085597603d6SJaroslav Kysela .remove = __devexit_p(loopback_remove), 1086597603d6SJaroslav Kysela #ifdef CONFIG_PM 1087597603d6SJaroslav Kysela .suspend = loopback_suspend, 1088597603d6SJaroslav Kysela .resume = loopback_resume, 1089597603d6SJaroslav Kysela #endif 1090597603d6SJaroslav Kysela .driver = { 1091597603d6SJaroslav Kysela .name = SND_LOOPBACK_DRIVER 1092597603d6SJaroslav Kysela }, 1093597603d6SJaroslav Kysela }; 1094597603d6SJaroslav Kysela 1095597603d6SJaroslav Kysela static void loopback_unregister_all(void) 1096597603d6SJaroslav Kysela { 1097597603d6SJaroslav Kysela int i; 1098597603d6SJaroslav Kysela 1099597603d6SJaroslav Kysela for (i = 0; i < ARRAY_SIZE(devices); ++i) 1100597603d6SJaroslav Kysela platform_device_unregister(devices[i]); 1101597603d6SJaroslav Kysela platform_driver_unregister(&loopback_driver); 1102597603d6SJaroslav Kysela } 1103597603d6SJaroslav Kysela 1104597603d6SJaroslav Kysela static int __init alsa_card_loopback_init(void) 1105597603d6SJaroslav Kysela { 1106597603d6SJaroslav Kysela int i, err, cards; 1107597603d6SJaroslav Kysela 1108597603d6SJaroslav Kysela err = platform_driver_register(&loopback_driver); 1109597603d6SJaroslav Kysela if (err < 0) 1110597603d6SJaroslav Kysela return err; 1111597603d6SJaroslav Kysela 1112597603d6SJaroslav Kysela 1113597603d6SJaroslav Kysela cards = 0; 1114597603d6SJaroslav Kysela for (i = 0; i < SNDRV_CARDS; i++) { 1115597603d6SJaroslav Kysela struct platform_device *device; 1116597603d6SJaroslav Kysela if (!enable[i]) 1117597603d6SJaroslav Kysela continue; 1118597603d6SJaroslav Kysela device = platform_device_register_simple(SND_LOOPBACK_DRIVER, 1119597603d6SJaroslav Kysela i, NULL, 0); 1120597603d6SJaroslav Kysela if (IS_ERR(device)) 1121597603d6SJaroslav Kysela continue; 1122597603d6SJaroslav Kysela if (!platform_get_drvdata(device)) { 1123597603d6SJaroslav Kysela platform_device_unregister(device); 1124597603d6SJaroslav Kysela continue; 1125597603d6SJaroslav Kysela } 1126597603d6SJaroslav Kysela devices[i] = device; 1127597603d6SJaroslav Kysela cards++; 1128597603d6SJaroslav Kysela } 1129597603d6SJaroslav Kysela if (!cards) { 1130597603d6SJaroslav Kysela #ifdef MODULE 1131597603d6SJaroslav Kysela printk(KERN_ERR "aloop: No loopback enabled\n"); 1132597603d6SJaroslav Kysela #endif 1133597603d6SJaroslav Kysela loopback_unregister_all(); 1134597603d6SJaroslav Kysela return -ENODEV; 1135597603d6SJaroslav Kysela } 1136597603d6SJaroslav Kysela return 0; 1137597603d6SJaroslav Kysela } 1138597603d6SJaroslav Kysela 1139597603d6SJaroslav Kysela static void __exit alsa_card_loopback_exit(void) 1140597603d6SJaroslav Kysela { 1141597603d6SJaroslav Kysela loopback_unregister_all(); 1142597603d6SJaroslav Kysela } 1143597603d6SJaroslav Kysela 1144597603d6SJaroslav Kysela module_init(alsa_card_loopback_init) 1145597603d6SJaroslav Kysela module_exit(alsa_card_loopback_exit) 1146