11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2597603d6SJaroslav Kysela /* 3597603d6SJaroslav Kysela * Loopback soundcard 4597603d6SJaroslav Kysela * 5597603d6SJaroslav Kysela * Original code: 6597603d6SJaroslav Kysela * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 7597603d6SJaroslav Kysela * 8597603d6SJaroslav Kysela * More accurate positioning and full-duplex support: 9597603d6SJaroslav Kysela * Copyright (c) Ahmet İnan <ainan at mathematik.uni-freiburg.de> 10597603d6SJaroslav Kysela * 11597603d6SJaroslav Kysela * Major (almost complete) rewrite: 12597603d6SJaroslav Kysela * Copyright (c) by Takashi Iwai <tiwai@suse.de> 13597603d6SJaroslav Kysela * 14597603d6SJaroslav Kysela * A next major update in 2010 (separate timers for playback and capture): 15597603d6SJaroslav Kysela * Copyright (c) Jaroslav Kysela <perex@perex.cz> 16597603d6SJaroslav Kysela */ 17597603d6SJaroslav Kysela 18597603d6SJaroslav Kysela #include <linux/init.h> 19597603d6SJaroslav Kysela #include <linux/jiffies.h> 20597603d6SJaroslav Kysela #include <linux/slab.h> 21597603d6SJaroslav Kysela #include <linux/time.h> 22597603d6SJaroslav Kysela #include <linux/wait.h> 2365a77217SPaul Gortmaker #include <linux/module.h> 24597603d6SJaroslav Kysela #include <linux/platform_device.h> 25597603d6SJaroslav Kysela #include <sound/core.h> 26597603d6SJaroslav Kysela #include <sound/control.h> 27597603d6SJaroslav Kysela #include <sound/pcm.h> 28b088b53eSTakashi Iwai #include <sound/pcm_params.h> 29e74670b6SJaroslav Kysela #include <sound/info.h> 30597603d6SJaroslav Kysela #include <sound/initval.h> 3126c53379STimo Wischer #include <sound/timer.h> 32597603d6SJaroslav Kysela 33597603d6SJaroslav Kysela MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 34597603d6SJaroslav Kysela MODULE_DESCRIPTION("A loopback soundcard"); 35597603d6SJaroslav Kysela MODULE_LICENSE("GPL"); 36597603d6SJaroslav Kysela MODULE_SUPPORTED_DEVICE("{{ALSA,Loopback soundcard}}"); 37597603d6SJaroslav Kysela 38597603d6SJaroslav Kysela #define MAX_PCM_SUBSTREAMS 8 39597603d6SJaroslav Kysela 40597603d6SJaroslav Kysela static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 41597603d6SJaroslav Kysela static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 42a67ff6a5SRusty Russell static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; 43597603d6SJaroslav Kysela static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; 44597603d6SJaroslav Kysela static int pcm_notify[SNDRV_CARDS]; 4526c53379STimo Wischer static char *timer_source[SNDRV_CARDS]; 46597603d6SJaroslav Kysela 47597603d6SJaroslav Kysela module_param_array(index, int, NULL, 0444); 48597603d6SJaroslav Kysela MODULE_PARM_DESC(index, "Index value for loopback soundcard."); 49597603d6SJaroslav Kysela module_param_array(id, charp, NULL, 0444); 50597603d6SJaroslav Kysela MODULE_PARM_DESC(id, "ID string for loopback soundcard."); 51597603d6SJaroslav Kysela module_param_array(enable, bool, NULL, 0444); 52597603d6SJaroslav Kysela MODULE_PARM_DESC(enable, "Enable this loopback soundcard."); 53597603d6SJaroslav Kysela module_param_array(pcm_substreams, int, NULL, 0444); 54597603d6SJaroslav Kysela MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver."); 55597603d6SJaroslav Kysela module_param_array(pcm_notify, int, NULL, 0444); 56597603d6SJaroslav Kysela MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes."); 5726c53379STimo Wischer module_param_array(timer_source, charp, NULL, 0444); 5826c53379STimo Wischer MODULE_PARM_DESC(timer_source, "Sound card name or number and device/subdevice number of timer to be used. Empty string for jiffies timer [default]."); 59597603d6SJaroslav Kysela 60597603d6SJaroslav Kysela #define NO_PITCH 100000 61597603d6SJaroslav Kysela 62fd1f7c74STimo Wischer #define CABLE_VALID_PLAYBACK BIT(SNDRV_PCM_STREAM_PLAYBACK) 63fd1f7c74STimo Wischer #define CABLE_VALID_CAPTURE BIT(SNDRV_PCM_STREAM_CAPTURE) 64fd1f7c74STimo Wischer #define CABLE_VALID_BOTH (CABLE_VALID_PLAYBACK | CABLE_VALID_CAPTURE) 65fd1f7c74STimo Wischer 66133f3759STimo Wischer struct loopback_cable; 67597603d6SJaroslav Kysela struct loopback_pcm; 68597603d6SJaroslav Kysela 69133f3759STimo Wischer struct loopback_ops { 70133f3759STimo Wischer /* optional 71133f3759STimo Wischer * call in loopback->cable_lock 72133f3759STimo Wischer */ 73133f3759STimo Wischer int (*open)(struct loopback_pcm *dpcm); 74133f3759STimo Wischer /* required 75133f3759STimo Wischer * call in cable->lock 76133f3759STimo Wischer */ 77133f3759STimo Wischer int (*start)(struct loopback_pcm *dpcm); 78133f3759STimo Wischer /* required 79133f3759STimo Wischer * call in cable->lock 80133f3759STimo Wischer */ 81133f3759STimo Wischer int (*stop)(struct loopback_pcm *dpcm); 82133f3759STimo Wischer /* optional */ 83133f3759STimo Wischer int (*stop_sync)(struct loopback_pcm *dpcm); 84133f3759STimo Wischer /* optional */ 85133f3759STimo Wischer int (*close_substream)(struct loopback_pcm *dpcm); 86133f3759STimo Wischer /* optional 87133f3759STimo Wischer * call in loopback->cable_lock 88133f3759STimo Wischer */ 89133f3759STimo Wischer int (*close_cable)(struct loopback_pcm *dpcm); 90133f3759STimo Wischer /* optional 91133f3759STimo Wischer * call in cable->lock 92133f3759STimo Wischer */ 93133f3759STimo Wischer unsigned int (*pos_update)(struct loopback_cable *cable); 94133f3759STimo Wischer /* optional */ 95133f3759STimo Wischer void (*dpcm_info)(struct loopback_pcm *dpcm, 96133f3759STimo Wischer struct snd_info_buffer *buffer); 97133f3759STimo Wischer }; 98133f3759STimo Wischer 99597603d6SJaroslav Kysela struct loopback_cable { 100597603d6SJaroslav Kysela spinlock_t lock; 101597603d6SJaroslav Kysela struct loopback_pcm *streams[2]; 102597603d6SJaroslav Kysela struct snd_pcm_hardware hw; 103597603d6SJaroslav Kysela /* flags */ 104597603d6SJaroslav Kysela unsigned int valid; 105597603d6SJaroslav Kysela unsigned int running; 1065de9e45fSJaroslav Kysela unsigned int pause; 107133f3759STimo Wischer /* timer specific */ 108133f3759STimo Wischer struct loopback_ops *ops; 10926c53379STimo Wischer /* If sound timer is used */ 11026c53379STimo Wischer struct { 11126c53379STimo Wischer int stream; 11226c53379STimo Wischer struct snd_timer_id id; 11326c53379STimo Wischer struct tasklet_struct event_tasklet; 11426c53379STimo Wischer struct snd_timer_instance *instance; 11526c53379STimo Wischer } snd_timer; 116597603d6SJaroslav Kysela }; 117597603d6SJaroslav Kysela 118597603d6SJaroslav Kysela struct loopback_setup { 119597603d6SJaroslav Kysela unsigned int notify: 1; 120597603d6SJaroslav Kysela unsigned int rate_shift; 121597603d6SJaroslav Kysela unsigned int format; 122597603d6SJaroslav Kysela unsigned int rate; 123597603d6SJaroslav Kysela unsigned int channels; 124597603d6SJaroslav Kysela struct snd_ctl_elem_id active_id; 125597603d6SJaroslav Kysela struct snd_ctl_elem_id format_id; 126597603d6SJaroslav Kysela struct snd_ctl_elem_id rate_id; 127597603d6SJaroslav Kysela struct snd_ctl_elem_id channels_id; 128597603d6SJaroslav Kysela }; 129597603d6SJaroslav Kysela 130597603d6SJaroslav Kysela struct loopback { 131597603d6SJaroslav Kysela struct snd_card *card; 132597603d6SJaroslav Kysela struct mutex cable_lock; 133597603d6SJaroslav Kysela struct loopback_cable *cables[MAX_PCM_SUBSTREAMS][2]; 134597603d6SJaroslav Kysela struct snd_pcm *pcm[2]; 135597603d6SJaroslav Kysela struct loopback_setup setup[MAX_PCM_SUBSTREAMS][2]; 13626c53379STimo Wischer const char *timer_source; 137597603d6SJaroslav Kysela }; 138597603d6SJaroslav Kysela 139597603d6SJaroslav Kysela struct loopback_pcm { 140597603d6SJaroslav Kysela struct loopback *loopback; 141597603d6SJaroslav Kysela struct snd_pcm_substream *substream; 142597603d6SJaroslav Kysela struct loopback_cable *cable; 143597603d6SJaroslav Kysela unsigned int pcm_buffer_size; 144597603d6SJaroslav Kysela unsigned int buf_pos; /* position in buffer */ 145597603d6SJaroslav Kysela unsigned int silent_size; 146597603d6SJaroslav Kysela /* PCM parameters */ 147597603d6SJaroslav Kysela unsigned int pcm_period_size; 148597603d6SJaroslav Kysela unsigned int pcm_bps; /* bytes per second */ 149597603d6SJaroslav Kysela unsigned int pcm_salign; /* bytes per sample * channels */ 150597603d6SJaroslav Kysela unsigned int pcm_rate_shift; /* rate shift value */ 151597603d6SJaroslav Kysela /* flags */ 152597603d6SJaroslav Kysela unsigned int period_update_pending :1; 153597603d6SJaroslav Kysela /* timer stuff */ 15497dda3daSTimo Wischer unsigned int irq_pos; /* fractional IRQ position in jiffies 15597dda3daSTimo Wischer * ticks 15697dda3daSTimo Wischer */ 15797dda3daSTimo Wischer unsigned int period_size_frac; /* period size in jiffies ticks */ 158b012513cSJaroslav Kysela unsigned int last_drift; 159597603d6SJaroslav Kysela unsigned long last_jiffies; 16026c53379STimo Wischer /* If jiffies timer is used */ 161597603d6SJaroslav Kysela struct timer_list timer; 162597603d6SJaroslav Kysela }; 163597603d6SJaroslav Kysela 164597603d6SJaroslav Kysela static struct platform_device *devices[SNDRV_CARDS]; 165597603d6SJaroslav Kysela 166597603d6SJaroslav Kysela static inline unsigned int byte_pos(struct loopback_pcm *dpcm, unsigned int x) 167597603d6SJaroslav Kysela { 168597603d6SJaroslav Kysela if (dpcm->pcm_rate_shift == NO_PITCH) { 169597603d6SJaroslav Kysela x /= HZ; 170597603d6SJaroslav Kysela } else { 171597603d6SJaroslav Kysela x = div_u64(NO_PITCH * (unsigned long long)x, 172597603d6SJaroslav Kysela HZ * (unsigned long long)dpcm->pcm_rate_shift); 173597603d6SJaroslav Kysela } 174597603d6SJaroslav Kysela return x - (x % dpcm->pcm_salign); 175597603d6SJaroslav Kysela } 176597603d6SJaroslav Kysela 177597603d6SJaroslav Kysela static inline unsigned int frac_pos(struct loopback_pcm *dpcm, unsigned int x) 178597603d6SJaroslav Kysela { 179597603d6SJaroslav Kysela if (dpcm->pcm_rate_shift == NO_PITCH) { /* no pitch */ 180597603d6SJaroslav Kysela return x * HZ; 181597603d6SJaroslav Kysela } else { 182597603d6SJaroslav Kysela x = div_u64(dpcm->pcm_rate_shift * (unsigned long long)x * HZ, 183597603d6SJaroslav Kysela NO_PITCH); 184597603d6SJaroslav Kysela } 185597603d6SJaroslav Kysela return x; 186597603d6SJaroslav Kysela } 187597603d6SJaroslav Kysela 188597603d6SJaroslav Kysela static inline struct loopback_setup *get_setup(struct loopback_pcm *dpcm) 189597603d6SJaroslav Kysela { 190597603d6SJaroslav Kysela int device = dpcm->substream->pstr->pcm->device; 191597603d6SJaroslav Kysela 192597603d6SJaroslav Kysela if (dpcm->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 193597603d6SJaroslav Kysela device ^= 1; 194597603d6SJaroslav Kysela return &dpcm->loopback->setup[dpcm->substream->number][device]; 195597603d6SJaroslav Kysela } 196597603d6SJaroslav Kysela 197597603d6SJaroslav Kysela static inline unsigned int get_notify(struct loopback_pcm *dpcm) 198597603d6SJaroslav Kysela { 199597603d6SJaroslav Kysela return get_setup(dpcm)->notify; 200597603d6SJaroslav Kysela } 201597603d6SJaroslav Kysela 202597603d6SJaroslav Kysela static inline unsigned int get_rate_shift(struct loopback_pcm *dpcm) 203597603d6SJaroslav Kysela { 204597603d6SJaroslav Kysela return get_setup(dpcm)->rate_shift; 205597603d6SJaroslav Kysela } 206597603d6SJaroslav Kysela 207999fc9f6STakashi Iwai /* call in cable->lock */ 2088e3bf7cdSTimo Wischer static int loopback_jiffies_timer_start(struct loopback_pcm *dpcm) 209597603d6SJaroslav Kysela { 210597603d6SJaroslav Kysela unsigned long tick; 211597603d6SJaroslav Kysela unsigned int rate_shift = get_rate_shift(dpcm); 212597603d6SJaroslav Kysela 213597603d6SJaroslav Kysela if (rate_shift != dpcm->pcm_rate_shift) { 214597603d6SJaroslav Kysela dpcm->pcm_rate_shift = rate_shift; 215597603d6SJaroslav Kysela dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size); 216597603d6SJaroslav Kysela } 2170db71023SJaroslav Kysela if (dpcm->period_size_frac <= dpcm->irq_pos) { 2180db71023SJaroslav Kysela dpcm->irq_pos %= dpcm->period_size_frac; 2190db71023SJaroslav Kysela dpcm->period_update_pending = 1; 2200db71023SJaroslav Kysela } 221597603d6SJaroslav Kysela tick = dpcm->period_size_frac - dpcm->irq_pos; 222597603d6SJaroslav Kysela tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps; 223db974553STakashi Iwai mod_timer(&dpcm->timer, jiffies + tick); 22409419f1aSTimo Wischer 22509419f1aSTimo Wischer return 0; 226597603d6SJaroslav Kysela } 227597603d6SJaroslav Kysela 228999fc9f6STakashi Iwai /* call in cable->lock */ 22926c53379STimo Wischer static int loopback_snd_timer_start(struct loopback_pcm *dpcm) 23026c53379STimo Wischer { 23126c53379STimo Wischer struct loopback_cable *cable = dpcm->cable; 23226c53379STimo Wischer int err; 23326c53379STimo Wischer 23426c53379STimo Wischer /* Loopback device has to use same period as timer card. Therefore 23526c53379STimo Wischer * wake up for each snd_pcm_period_elapsed() call of timer card. 23626c53379STimo Wischer */ 23726c53379STimo Wischer err = snd_timer_start(cable->snd_timer.instance, 1); 23826c53379STimo Wischer if (err < 0) { 23926c53379STimo Wischer /* do not report error if trying to start but already 24026c53379STimo Wischer * running. For example called by opposite substream 24126c53379STimo Wischer * of the same cable 24226c53379STimo Wischer */ 24326c53379STimo Wischer if (err == -EBUSY) 24426c53379STimo Wischer return 0; 24526c53379STimo Wischer 24626c53379STimo Wischer pcm_err(dpcm->substream->pcm, 24726c53379STimo Wischer "snd_timer_start(%d,%d,%d) failed with %d", 24826c53379STimo Wischer cable->snd_timer.id.card, 24926c53379STimo Wischer cable->snd_timer.id.device, 25026c53379STimo Wischer cable->snd_timer.id.subdevice, 25126c53379STimo Wischer err); 25226c53379STimo Wischer } 25326c53379STimo Wischer 25426c53379STimo Wischer return err; 25526c53379STimo Wischer } 25626c53379STimo Wischer 25726c53379STimo Wischer /* call in cable->lock */ 2588e3bf7cdSTimo Wischer static inline int loopback_jiffies_timer_stop(struct loopback_pcm *dpcm) 259597603d6SJaroslav Kysela { 260597603d6SJaroslav Kysela del_timer(&dpcm->timer); 261e74670b6SJaroslav Kysela dpcm->timer.expires = 0; 26209419f1aSTimo Wischer 26309419f1aSTimo Wischer return 0; 264597603d6SJaroslav Kysela } 265597603d6SJaroslav Kysela 26626c53379STimo Wischer /* call in cable->lock */ 26726c53379STimo Wischer static int loopback_snd_timer_stop(struct loopback_pcm *dpcm) 26826c53379STimo Wischer { 26926c53379STimo Wischer struct loopback_cable *cable = dpcm->cable; 27026c53379STimo Wischer int err; 27126c53379STimo Wischer 27226c53379STimo Wischer /* only stop if both devices (playback and capture) are not running */ 27326c53379STimo Wischer if (cable->running ^ cable->pause) 27426c53379STimo Wischer return 0; 27526c53379STimo Wischer 27626c53379STimo Wischer err = snd_timer_stop(cable->snd_timer.instance); 27726c53379STimo Wischer if (err < 0) { 27826c53379STimo Wischer pcm_err(dpcm->substream->pcm, 27926c53379STimo Wischer "snd_timer_stop(%d,%d,%d) failed with %d", 28026c53379STimo Wischer cable->snd_timer.id.card, 28126c53379STimo Wischer cable->snd_timer.id.device, 28226c53379STimo Wischer cable->snd_timer.id.subdevice, 28326c53379STimo Wischer err); 28426c53379STimo Wischer } 28526c53379STimo Wischer 28626c53379STimo Wischer return err; 28726c53379STimo Wischer } 28826c53379STimo Wischer 2898e3bf7cdSTimo Wischer static inline int loopback_jiffies_timer_stop_sync(struct loopback_pcm *dpcm) 29067a01afaSTakashi Iwai { 29167a01afaSTakashi Iwai del_timer_sync(&dpcm->timer); 29209419f1aSTimo Wischer 29309419f1aSTimo Wischer return 0; 29467a01afaSTakashi Iwai } 29567a01afaSTakashi Iwai 29626c53379STimo Wischer /* call in loopback->cable_lock */ 29726c53379STimo Wischer static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm) 29826c53379STimo Wischer { 29926c53379STimo Wischer struct loopback_cable *cable = dpcm->cable; 30026c53379STimo Wischer 30126c53379STimo Wischer /* snd_timer was not opened */ 30226c53379STimo Wischer if (!cable->snd_timer.instance) 30326c53379STimo Wischer return 0; 30426c53379STimo Wischer 30526c53379STimo Wischer /* will only be called from free_cable() when other stream was 30626c53379STimo Wischer * already closed. Other stream cannot be reopened as long as 30726c53379STimo Wischer * loopback->cable_lock is locked. Therefore no need to lock 30826c53379STimo Wischer * cable->lock; 30926c53379STimo Wischer */ 31026c53379STimo Wischer snd_timer_close(cable->snd_timer.instance); 3119314e44fSAndrew Gabbasov 3129314e44fSAndrew Gabbasov /* wait till drain tasklet has finished if requested */ 3139314e44fSAndrew Gabbasov tasklet_kill(&cable->snd_timer.event_tasklet); 3149314e44fSAndrew Gabbasov 31526c53379STimo Wischer snd_timer_instance_free(cable->snd_timer.instance); 31626c53379STimo Wischer memset(&cable->snd_timer, 0, sizeof(cable->snd_timer)); 31726c53379STimo Wischer 31826c53379STimo Wischer return 0; 31926c53379STimo Wischer } 32026c53379STimo Wischer 321597603d6SJaroslav Kysela static int loopback_check_format(struct loopback_cable *cable, int stream) 322597603d6SJaroslav Kysela { 323b1c73fc8SJaroslav Kysela struct snd_pcm_runtime *runtime, *cruntime; 324597603d6SJaroslav Kysela struct loopback_setup *setup; 325597603d6SJaroslav Kysela struct snd_card *card; 326597603d6SJaroslav Kysela int check; 327597603d6SJaroslav Kysela 328597603d6SJaroslav Kysela if (cable->valid != CABLE_VALID_BOTH) { 329597603d6SJaroslav Kysela if (stream == SNDRV_PCM_STREAM_PLAYBACK) 330597603d6SJaroslav Kysela goto __notify; 331597603d6SJaroslav Kysela return 0; 332597603d6SJaroslav Kysela } 333597603d6SJaroslav Kysela runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> 334597603d6SJaroslav Kysela substream->runtime; 335b1c73fc8SJaroslav Kysela cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> 336b1c73fc8SJaroslav Kysela substream->runtime; 337b1c73fc8SJaroslav Kysela check = runtime->format != cruntime->format || 338b1c73fc8SJaroslav Kysela runtime->rate != cruntime->rate || 339b1c73fc8SJaroslav Kysela runtime->channels != cruntime->channels; 340597603d6SJaroslav Kysela if (!check) 341597603d6SJaroslav Kysela return 0; 342597603d6SJaroslav Kysela if (stream == SNDRV_PCM_STREAM_CAPTURE) { 343597603d6SJaroslav Kysela return -EIO; 344597603d6SJaroslav Kysela } else { 345597603d6SJaroslav Kysela snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> 346597603d6SJaroslav Kysela substream, SNDRV_PCM_STATE_DRAINING); 347597603d6SJaroslav Kysela __notify: 348597603d6SJaroslav Kysela runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> 349597603d6SJaroslav Kysela substream->runtime; 350597603d6SJaroslav Kysela setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]); 351597603d6SJaroslav Kysela card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card; 352597603d6SJaroslav Kysela if (setup->format != runtime->format) { 353597603d6SJaroslav Kysela snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, 354597603d6SJaroslav Kysela &setup->format_id); 355597603d6SJaroslav Kysela setup->format = runtime->format; 356597603d6SJaroslav Kysela } 357597603d6SJaroslav Kysela if (setup->rate != runtime->rate) { 358597603d6SJaroslav Kysela snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, 359597603d6SJaroslav Kysela &setup->rate_id); 360597603d6SJaroslav Kysela setup->rate = runtime->rate; 361597603d6SJaroslav Kysela } 362597603d6SJaroslav Kysela if (setup->channels != runtime->channels) { 363597603d6SJaroslav Kysela snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, 364597603d6SJaroslav Kysela &setup->channels_id); 365597603d6SJaroslav Kysela setup->channels = runtime->channels; 366597603d6SJaroslav Kysela } 367597603d6SJaroslav Kysela } 368597603d6SJaroslav Kysela return 0; 369597603d6SJaroslav Kysela } 370597603d6SJaroslav Kysela 371597603d6SJaroslav Kysela static void loopback_active_notify(struct loopback_pcm *dpcm) 372597603d6SJaroslav Kysela { 373597603d6SJaroslav Kysela snd_ctl_notify(dpcm->loopback->card, 374597603d6SJaroslav Kysela SNDRV_CTL_EVENT_MASK_VALUE, 375597603d6SJaroslav Kysela &get_setup(dpcm)->active_id); 376597603d6SJaroslav Kysela } 377597603d6SJaroslav Kysela 378597603d6SJaroslav Kysela static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) 379597603d6SJaroslav Kysela { 380597603d6SJaroslav Kysela struct snd_pcm_runtime *runtime = substream->runtime; 381597603d6SJaroslav Kysela struct loopback_pcm *dpcm = runtime->private_data; 382597603d6SJaroslav Kysela struct loopback_cable *cable = dpcm->cable; 38309419f1aSTimo Wischer int err = 0, stream = 1 << substream->stream; 384597603d6SJaroslav Kysela 385597603d6SJaroslav Kysela switch (cmd) { 386597603d6SJaroslav Kysela case SNDRV_PCM_TRIGGER_START: 387597603d6SJaroslav Kysela err = loopback_check_format(cable, substream->stream); 388597603d6SJaroslav Kysela if (err < 0) 389597603d6SJaroslav Kysela return err; 390597603d6SJaroslav Kysela dpcm->last_jiffies = jiffies; 391597603d6SJaroslav Kysela dpcm->pcm_rate_shift = 0; 392b012513cSJaroslav Kysela dpcm->last_drift = 0; 393dd04bb12SJaroslav Kysela spin_lock(&cable->lock); 3945de9e45fSJaroslav Kysela cable->running |= stream; 3955de9e45fSJaroslav Kysela cable->pause &= ~stream; 396133f3759STimo Wischer err = cable->ops->start(dpcm); 397999fc9f6STakashi Iwai spin_unlock(&cable->lock); 398597603d6SJaroslav Kysela if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 399597603d6SJaroslav Kysela loopback_active_notify(dpcm); 400597603d6SJaroslav Kysela break; 401597603d6SJaroslav Kysela case SNDRV_PCM_TRIGGER_STOP: 402dd04bb12SJaroslav Kysela spin_lock(&cable->lock); 4035de9e45fSJaroslav Kysela cable->running &= ~stream; 4045de9e45fSJaroslav Kysela cable->pause &= ~stream; 405133f3759STimo Wischer err = cable->ops->stop(dpcm); 406999fc9f6STakashi Iwai spin_unlock(&cable->lock); 407597603d6SJaroslav Kysela if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 408597603d6SJaroslav Kysela loopback_active_notify(dpcm); 409597603d6SJaroslav Kysela break; 4105de9e45fSJaroslav Kysela case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 411edac8943STakashi Iwai case SNDRV_PCM_TRIGGER_SUSPEND: 4125de9e45fSJaroslav Kysela spin_lock(&cable->lock); 4135de9e45fSJaroslav Kysela cable->pause |= stream; 414133f3759STimo Wischer err = cable->ops->stop(dpcm); 415999fc9f6STakashi Iwai spin_unlock(&cable->lock); 416306a4f3cSRobert Rosengren if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 417306a4f3cSRobert Rosengren loopback_active_notify(dpcm); 4185de9e45fSJaroslav Kysela break; 4195de9e45fSJaroslav Kysela case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 420edac8943STakashi Iwai case SNDRV_PCM_TRIGGER_RESUME: 4215de9e45fSJaroslav Kysela spin_lock(&cable->lock); 4225de9e45fSJaroslav Kysela dpcm->last_jiffies = jiffies; 4235de9e45fSJaroslav Kysela cable->pause &= ~stream; 424133f3759STimo Wischer err = cable->ops->start(dpcm); 425999fc9f6STakashi Iwai spin_unlock(&cable->lock); 426306a4f3cSRobert Rosengren if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 427306a4f3cSRobert Rosengren loopback_active_notify(dpcm); 4285de9e45fSJaroslav Kysela break; 429597603d6SJaroslav Kysela default: 430597603d6SJaroslav Kysela return -EINVAL; 431597603d6SJaroslav Kysela } 43209419f1aSTimo Wischer return err; 433597603d6SJaroslav Kysela } 434597603d6SJaroslav Kysela 435b1c73fc8SJaroslav Kysela static void params_change(struct snd_pcm_substream *substream) 436b1c73fc8SJaroslav Kysela { 437b1c73fc8SJaroslav Kysela struct snd_pcm_runtime *runtime = substream->runtime; 438b1c73fc8SJaroslav Kysela struct loopback_pcm *dpcm = runtime->private_data; 439b1c73fc8SJaroslav Kysela struct loopback_cable *cable = dpcm->cable; 440b1c73fc8SJaroslav Kysela 44174c34ca1SEldad Zack cable->hw.formats = pcm_format_to_bits(runtime->format); 442b1c73fc8SJaroslav Kysela cable->hw.rate_min = runtime->rate; 443b1c73fc8SJaroslav Kysela cable->hw.rate_max = runtime->rate; 444b1c73fc8SJaroslav Kysela cable->hw.channels_min = runtime->channels; 445b1c73fc8SJaroslav Kysela cable->hw.channels_max = runtime->channels; 44626c53379STimo Wischer 44726c53379STimo Wischer if (cable->snd_timer.instance) { 44826c53379STimo Wischer cable->hw.period_bytes_min = 44926c53379STimo Wischer frames_to_bytes(runtime, runtime->period_size); 45026c53379STimo Wischer cable->hw.period_bytes_max = cable->hw.period_bytes_min; 45126c53379STimo Wischer } 45226c53379STimo Wischer 453b1c73fc8SJaroslav Kysela } 454b1c73fc8SJaroslav Kysela 455597603d6SJaroslav Kysela static int loopback_prepare(struct snd_pcm_substream *substream) 456597603d6SJaroslav Kysela { 457597603d6SJaroslav Kysela struct snd_pcm_runtime *runtime = substream->runtime; 458597603d6SJaroslav Kysela struct loopback_pcm *dpcm = runtime->private_data; 459597603d6SJaroslav Kysela struct loopback_cable *cable = dpcm->cable; 46009419f1aSTimo Wischer int err, bps, salign; 461597603d6SJaroslav Kysela 462133f3759STimo Wischer if (cable->ops->stop_sync) { 463133f3759STimo Wischer err = cable->ops->stop_sync(dpcm); 46409419f1aSTimo Wischer if (err < 0) 46509419f1aSTimo Wischer return err; 466133f3759STimo Wischer } 46767a01afaSTakashi Iwai 46850e09084STimo Wischer salign = (snd_pcm_format_physical_width(runtime->format) * 469597603d6SJaroslav Kysela runtime->channels) / 8; 470597603d6SJaroslav Kysela bps = salign * runtime->rate; 471597603d6SJaroslav Kysela if (bps <= 0 || salign <= 0) 472597603d6SJaroslav Kysela return -EINVAL; 473597603d6SJaroslav Kysela 474597603d6SJaroslav Kysela dpcm->buf_pos = 0; 475597603d6SJaroslav Kysela dpcm->pcm_buffer_size = frames_to_bytes(runtime, runtime->buffer_size); 476597603d6SJaroslav Kysela if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 477597603d6SJaroslav Kysela /* clear capture buffer */ 478597603d6SJaroslav Kysela dpcm->silent_size = dpcm->pcm_buffer_size; 479597603d6SJaroslav Kysela snd_pcm_format_set_silence(runtime->format, runtime->dma_area, 480597603d6SJaroslav Kysela runtime->buffer_size * runtime->channels); 481597603d6SJaroslav Kysela } 482597603d6SJaroslav Kysela 483597603d6SJaroslav Kysela dpcm->irq_pos = 0; 484597603d6SJaroslav Kysela dpcm->period_update_pending = 0; 485597603d6SJaroslav Kysela dpcm->pcm_bps = bps; 486597603d6SJaroslav Kysela dpcm->pcm_salign = salign; 487597603d6SJaroslav Kysela dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size); 488597603d6SJaroslav Kysela 489597603d6SJaroslav Kysela mutex_lock(&dpcm->loopback->cable_lock); 490b1c73fc8SJaroslav Kysela if (!(cable->valid & ~(1 << substream->stream)) || 491b1c73fc8SJaroslav Kysela (get_setup(dpcm)->notify && 492b1c73fc8SJaroslav Kysela substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) 493b1c73fc8SJaroslav Kysela params_change(substream); 494597603d6SJaroslav Kysela cable->valid |= 1 << substream->stream; 495597603d6SJaroslav Kysela mutex_unlock(&dpcm->loopback->cable_lock); 496597603d6SJaroslav Kysela 497597603d6SJaroslav Kysela return 0; 498597603d6SJaroslav Kysela } 499597603d6SJaroslav Kysela 500597603d6SJaroslav Kysela static void clear_capture_buf(struct loopback_pcm *dpcm, unsigned int bytes) 501597603d6SJaroslav Kysela { 502597603d6SJaroslav Kysela struct snd_pcm_runtime *runtime = dpcm->substream->runtime; 503597603d6SJaroslav Kysela char *dst = runtime->dma_area; 504597603d6SJaroslav Kysela unsigned int dst_off = dpcm->buf_pos; 505597603d6SJaroslav Kysela 506597603d6SJaroslav Kysela if (dpcm->silent_size >= dpcm->pcm_buffer_size) 507597603d6SJaroslav Kysela return; 508597603d6SJaroslav Kysela if (dpcm->silent_size + bytes > dpcm->pcm_buffer_size) 509597603d6SJaroslav Kysela bytes = dpcm->pcm_buffer_size - dpcm->silent_size; 510597603d6SJaroslav Kysela 511597603d6SJaroslav Kysela for (;;) { 512597603d6SJaroslav Kysela unsigned int size = bytes; 513597603d6SJaroslav Kysela if (dst_off + size > dpcm->pcm_buffer_size) 514597603d6SJaroslav Kysela size = dpcm->pcm_buffer_size - dst_off; 515597603d6SJaroslav Kysela snd_pcm_format_set_silence(runtime->format, dst + dst_off, 516597603d6SJaroslav Kysela bytes_to_frames(runtime, size) * 517597603d6SJaroslav Kysela runtime->channels); 518597603d6SJaroslav Kysela dpcm->silent_size += size; 519597603d6SJaroslav Kysela bytes -= size; 520597603d6SJaroslav Kysela if (!bytes) 521597603d6SJaroslav Kysela break; 522597603d6SJaroslav Kysela dst_off = 0; 523597603d6SJaroslav Kysela } 524597603d6SJaroslav Kysela } 525597603d6SJaroslav Kysela 526597603d6SJaroslav Kysela static void copy_play_buf(struct loopback_pcm *play, 527597603d6SJaroslav Kysela struct loopback_pcm *capt, 528597603d6SJaroslav Kysela unsigned int bytes) 529597603d6SJaroslav Kysela { 530597603d6SJaroslav Kysela struct snd_pcm_runtime *runtime = play->substream->runtime; 53120d9a26dSJaroslav Kysela char *src = runtime->dma_area; 532597603d6SJaroslav Kysela char *dst = capt->substream->runtime->dma_area; 533597603d6SJaroslav Kysela unsigned int src_off = play->buf_pos; 534597603d6SJaroslav Kysela unsigned int dst_off = capt->buf_pos; 535597603d6SJaroslav Kysela unsigned int clear_bytes = 0; 536597603d6SJaroslav Kysela 537597603d6SJaroslav Kysela /* check if playback is draining, trim the capture copy size 538597603d6SJaroslav Kysela * when our pointer is at the end of playback ring buffer */ 539597603d6SJaroslav Kysela if (runtime->status->state == SNDRV_PCM_STATE_DRAINING && 540597603d6SJaroslav Kysela snd_pcm_playback_hw_avail(runtime) < runtime->buffer_size) { 541597603d6SJaroslav Kysela snd_pcm_uframes_t appl_ptr, appl_ptr1, diff; 542597603d6SJaroslav Kysela appl_ptr = appl_ptr1 = runtime->control->appl_ptr; 543597603d6SJaroslav Kysela appl_ptr1 -= appl_ptr1 % runtime->buffer_size; 544597603d6SJaroslav Kysela appl_ptr1 += play->buf_pos / play->pcm_salign; 545597603d6SJaroslav Kysela if (appl_ptr < appl_ptr1) 546597603d6SJaroslav Kysela appl_ptr1 -= runtime->buffer_size; 547597603d6SJaroslav Kysela diff = (appl_ptr - appl_ptr1) * play->pcm_salign; 548597603d6SJaroslav Kysela if (diff < bytes) { 549597603d6SJaroslav Kysela clear_bytes = bytes - diff; 550597603d6SJaroslav Kysela bytes = diff; 551597603d6SJaroslav Kysela } 552597603d6SJaroslav Kysela } 553597603d6SJaroslav Kysela 554597603d6SJaroslav Kysela for (;;) { 555597603d6SJaroslav Kysela unsigned int size = bytes; 556597603d6SJaroslav Kysela if (src_off + size > play->pcm_buffer_size) 557597603d6SJaroslav Kysela size = play->pcm_buffer_size - src_off; 558597603d6SJaroslav Kysela if (dst_off + size > capt->pcm_buffer_size) 559597603d6SJaroslav Kysela size = capt->pcm_buffer_size - dst_off; 560597603d6SJaroslav Kysela memcpy(dst + dst_off, src + src_off, size); 561597603d6SJaroslav Kysela capt->silent_size = 0; 562597603d6SJaroslav Kysela bytes -= size; 563597603d6SJaroslav Kysela if (!bytes) 564597603d6SJaroslav Kysela break; 565597603d6SJaroslav Kysela src_off = (src_off + size) % play->pcm_buffer_size; 566597603d6SJaroslav Kysela dst_off = (dst_off + size) % capt->pcm_buffer_size; 567597603d6SJaroslav Kysela } 568597603d6SJaroslav Kysela 56920d9a26dSJaroslav Kysela if (clear_bytes > 0) { 570597603d6SJaroslav Kysela clear_capture_buf(capt, clear_bytes); 57120d9a26dSJaroslav Kysela capt->silent_size = 0; 57220d9a26dSJaroslav Kysela } 573597603d6SJaroslav Kysela } 574597603d6SJaroslav Kysela 575b012513cSJaroslav Kysela static inline unsigned int bytepos_delta(struct loopback_pcm *dpcm, 576b012513cSJaroslav Kysela unsigned int jiffies_delta) 577597603d6SJaroslav Kysela { 578597603d6SJaroslav Kysela unsigned long last_pos; 579b012513cSJaroslav Kysela unsigned int delta; 580597603d6SJaroslav Kysela 581597603d6SJaroslav Kysela last_pos = byte_pos(dpcm, dpcm->irq_pos); 582b012513cSJaroslav Kysela dpcm->irq_pos += jiffies_delta * dpcm->pcm_bps; 583b012513cSJaroslav Kysela delta = byte_pos(dpcm, dpcm->irq_pos) - last_pos; 584b012513cSJaroslav Kysela if (delta >= dpcm->last_drift) 585b012513cSJaroslav Kysela delta -= dpcm->last_drift; 586b012513cSJaroslav Kysela dpcm->last_drift = 0; 587597603d6SJaroslav Kysela if (dpcm->irq_pos >= dpcm->period_size_frac) { 588597603d6SJaroslav Kysela dpcm->irq_pos %= dpcm->period_size_frac; 589597603d6SJaroslav Kysela dpcm->period_update_pending = 1; 590597603d6SJaroslav Kysela } 591b012513cSJaroslav Kysela return delta; 592b012513cSJaroslav Kysela } 593b012513cSJaroslav Kysela 594b012513cSJaroslav Kysela static inline void bytepos_finish(struct loopback_pcm *dpcm, 595b012513cSJaroslav Kysela unsigned int delta) 596b012513cSJaroslav Kysela { 597b012513cSJaroslav Kysela dpcm->buf_pos += delta; 598b012513cSJaroslav Kysela dpcm->buf_pos %= dpcm->pcm_buffer_size; 599597603d6SJaroslav Kysela } 600597603d6SJaroslav Kysela 601999fc9f6STakashi Iwai /* call in cable->lock */ 6028e3bf7cdSTimo Wischer static unsigned int loopback_jiffies_timer_pos_update 6038e3bf7cdSTimo Wischer (struct loopback_cable *cable) 604597603d6SJaroslav Kysela { 605597603d6SJaroslav Kysela struct loopback_pcm *dpcm_play = 606597603d6SJaroslav Kysela cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; 607597603d6SJaroslav Kysela struct loopback_pcm *dpcm_capt = 608597603d6SJaroslav Kysela cable->streams[SNDRV_PCM_STREAM_CAPTURE]; 609597603d6SJaroslav Kysela unsigned long delta_play = 0, delta_capt = 0; 610b012513cSJaroslav Kysela unsigned int running, count1, count2; 611597603d6SJaroslav Kysela 6125de9e45fSJaroslav Kysela running = cable->running ^ cable->pause; 613dd04bb12SJaroslav Kysela if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { 614597603d6SJaroslav Kysela delta_play = jiffies - dpcm_play->last_jiffies; 615597603d6SJaroslav Kysela dpcm_play->last_jiffies += delta_play; 616597603d6SJaroslav Kysela } 617597603d6SJaroslav Kysela 618dd04bb12SJaroslav Kysela if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) { 619597603d6SJaroslav Kysela delta_capt = jiffies - dpcm_capt->last_jiffies; 620597603d6SJaroslav Kysela dpcm_capt->last_jiffies += delta_capt; 621597603d6SJaroslav Kysela } 622597603d6SJaroslav Kysela 62398d21df4STakashi Iwai if (delta_play == 0 && delta_capt == 0) 62498d21df4STakashi Iwai goto unlock; 625597603d6SJaroslav Kysela 626597603d6SJaroslav Kysela if (delta_play > delta_capt) { 627b012513cSJaroslav Kysela count1 = bytepos_delta(dpcm_play, delta_play - delta_capt); 628b012513cSJaroslav Kysela bytepos_finish(dpcm_play, count1); 629597603d6SJaroslav Kysela delta_play = delta_capt; 630597603d6SJaroslav Kysela } else if (delta_play < delta_capt) { 631b012513cSJaroslav Kysela count1 = bytepos_delta(dpcm_capt, delta_capt - delta_play); 632b012513cSJaroslav Kysela clear_capture_buf(dpcm_capt, count1); 633b012513cSJaroslav Kysela bytepos_finish(dpcm_capt, count1); 634597603d6SJaroslav Kysela delta_capt = delta_play; 635597603d6SJaroslav Kysela } 636597603d6SJaroslav Kysela 63798d21df4STakashi Iwai if (delta_play == 0 && delta_capt == 0) 63898d21df4STakashi Iwai goto unlock; 63998d21df4STakashi Iwai 640597603d6SJaroslav Kysela /* note delta_capt == delta_play at this moment */ 641b012513cSJaroslav Kysela count1 = bytepos_delta(dpcm_play, delta_play); 642b012513cSJaroslav Kysela count2 = bytepos_delta(dpcm_capt, delta_capt); 643b012513cSJaroslav Kysela if (count1 < count2) { 644b012513cSJaroslav Kysela dpcm_capt->last_drift = count2 - count1; 645b012513cSJaroslav Kysela count1 = count2; 646b012513cSJaroslav Kysela } else if (count1 > count2) { 647b012513cSJaroslav Kysela dpcm_play->last_drift = count1 - count2; 648b012513cSJaroslav Kysela } 649b012513cSJaroslav Kysela copy_play_buf(dpcm_play, dpcm_capt, count1); 650b012513cSJaroslav Kysela bytepos_finish(dpcm_play, count1); 651b012513cSJaroslav Kysela bytepos_finish(dpcm_capt, count1); 65298d21df4STakashi Iwai unlock: 653dd04bb12SJaroslav Kysela return running; 654597603d6SJaroslav Kysela } 655597603d6SJaroslav Kysela 6568e3bf7cdSTimo Wischer static void loopback_jiffies_timer_function(struct timer_list *t) 657597603d6SJaroslav Kysela { 658bc47ba90SKees Cook struct loopback_pcm *dpcm = from_timer(dpcm, t, timer); 659999fc9f6STakashi Iwai unsigned long flags; 660597603d6SJaroslav Kysela 661999fc9f6STakashi Iwai spin_lock_irqsave(&dpcm->cable->lock, flags); 6628e3bf7cdSTimo Wischer if (loopback_jiffies_timer_pos_update(dpcm->cable) & 6638e3bf7cdSTimo Wischer (1 << dpcm->substream->stream)) { 6648e3bf7cdSTimo Wischer loopback_jiffies_timer_start(dpcm); 665597603d6SJaroslav Kysela if (dpcm->period_update_pending) { 666597603d6SJaroslav Kysela dpcm->period_update_pending = 0; 667999fc9f6STakashi Iwai spin_unlock_irqrestore(&dpcm->cable->lock, flags); 668999fc9f6STakashi Iwai /* need to unlock before calling below */ 669597603d6SJaroslav Kysela snd_pcm_period_elapsed(dpcm->substream); 670999fc9f6STakashi Iwai return; 671597603d6SJaroslav Kysela } 672597603d6SJaroslav Kysela } 673999fc9f6STakashi Iwai spin_unlock_irqrestore(&dpcm->cable->lock, flags); 674dd04bb12SJaroslav Kysela } 675597603d6SJaroslav Kysela 67626c53379STimo Wischer /* call in cable->lock */ 67726c53379STimo Wischer static int loopback_snd_timer_check_resolution(struct snd_pcm_runtime *runtime, 67826c53379STimo Wischer unsigned long resolution) 67926c53379STimo Wischer { 68026c53379STimo Wischer if (resolution != runtime->timer_resolution) { 68126c53379STimo Wischer struct loopback_pcm *dpcm = runtime->private_data; 68226c53379STimo Wischer struct loopback_cable *cable = dpcm->cable; 68326c53379STimo Wischer /* Worst case estimation of possible values for resolution 68426c53379STimo Wischer * resolution <= (512 * 1024) frames / 8kHz in nsec 68526c53379STimo Wischer * resolution <= 65.536.000.000 nsec 68626c53379STimo Wischer * 68726c53379STimo Wischer * period_size <= 65.536.000.000 nsec / 1000nsec/usec * 192kHz + 68826c53379STimo Wischer * 500.000 68926c53379STimo Wischer * period_size <= 12.582.912.000.000 <64bit 69026c53379STimo Wischer * / 1.000.000 usec/sec 69126c53379STimo Wischer */ 69226c53379STimo Wischer snd_pcm_uframes_t period_size_usec = 69326c53379STimo Wischer resolution / 1000 * runtime->rate; 69426c53379STimo Wischer /* round to nearest sample rate */ 69526c53379STimo Wischer snd_pcm_uframes_t period_size = 69626c53379STimo Wischer (period_size_usec + 500 * 1000) / (1000 * 1000); 69726c53379STimo Wischer 69826c53379STimo Wischer pcm_err(dpcm->substream->pcm, 69926c53379STimo Wischer "Period size (%lu frames) of loopback device is not corresponding to timer resolution (%lu nsec = %lu frames) of card timer %d,%d,%d. Use period size of %lu frames for loopback device.", 70026c53379STimo Wischer runtime->period_size, resolution, period_size, 70126c53379STimo Wischer cable->snd_timer.id.card, 70226c53379STimo Wischer cable->snd_timer.id.device, 70326c53379STimo Wischer cable->snd_timer.id.subdevice, 70426c53379STimo Wischer period_size); 70526c53379STimo Wischer return -EINVAL; 70626c53379STimo Wischer } 70726c53379STimo Wischer return 0; 70826c53379STimo Wischer } 70926c53379STimo Wischer 71026c53379STimo Wischer static void loopback_snd_timer_period_elapsed(struct loopback_cable *cable, 71126c53379STimo Wischer int event, 71226c53379STimo Wischer unsigned long resolution) 71326c53379STimo Wischer { 71426c53379STimo Wischer struct loopback_pcm *dpcm_play, *dpcm_capt; 71526c53379STimo Wischer struct snd_pcm_substream *substream_play, *substream_capt; 71626c53379STimo Wischer struct snd_pcm_runtime *valid_runtime; 71726c53379STimo Wischer unsigned int running, elapsed_bytes; 71826c53379STimo Wischer unsigned long flags; 71926c53379STimo Wischer 72026c53379STimo Wischer spin_lock_irqsave(&cable->lock, flags); 72126c53379STimo Wischer running = cable->running ^ cable->pause; 72226c53379STimo Wischer /* no need to do anything if no stream is running */ 72326c53379STimo Wischer if (!running) { 72426c53379STimo Wischer spin_unlock_irqrestore(&cable->lock, flags); 72526c53379STimo Wischer return; 72626c53379STimo Wischer } 72726c53379STimo Wischer 72826c53379STimo Wischer dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; 72926c53379STimo Wischer dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE]; 73026c53379STimo Wischer 73126c53379STimo Wischer if (event == SNDRV_TIMER_EVENT_MSTOP) { 73226c53379STimo Wischer if (!dpcm_play || 73326c53379STimo Wischer dpcm_play->substream->runtime->status->state != 73426c53379STimo Wischer SNDRV_PCM_STATE_DRAINING) { 73526c53379STimo Wischer spin_unlock_irqrestore(&cable->lock, flags); 73626c53379STimo Wischer return; 73726c53379STimo Wischer } 73826c53379STimo Wischer } 73926c53379STimo Wischer 7405061bb70SAndrew Gabbasov substream_play = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? 7415061bb70SAndrew Gabbasov dpcm_play->substream : NULL; 7425061bb70SAndrew Gabbasov substream_capt = (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) ? 7435061bb70SAndrew Gabbasov dpcm_capt->substream : NULL; 74426c53379STimo Wischer valid_runtime = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? 74526c53379STimo Wischer dpcm_play->substream->runtime : 74626c53379STimo Wischer dpcm_capt->substream->runtime; 74726c53379STimo Wischer 74826c53379STimo Wischer /* resolution is only valid for SNDRV_TIMER_EVENT_TICK events */ 74926c53379STimo Wischer if (event == SNDRV_TIMER_EVENT_TICK) { 75026c53379STimo Wischer /* The hardware rules guarantee that playback and capture period 75126c53379STimo Wischer * are the same. Therefore only one device has to be checked 75226c53379STimo Wischer * here. 75326c53379STimo Wischer */ 75426c53379STimo Wischer if (loopback_snd_timer_check_resolution(valid_runtime, 75526c53379STimo Wischer resolution) < 0) { 75626c53379STimo Wischer spin_unlock_irqrestore(&cable->lock, flags); 75726c53379STimo Wischer if (substream_play) 75826c53379STimo Wischer snd_pcm_stop_xrun(substream_play); 75926c53379STimo Wischer if (substream_capt) 76026c53379STimo Wischer snd_pcm_stop_xrun(substream_capt); 76126c53379STimo Wischer return; 76226c53379STimo Wischer } 76326c53379STimo Wischer } 76426c53379STimo Wischer 76526c53379STimo Wischer elapsed_bytes = frames_to_bytes(valid_runtime, 76626c53379STimo Wischer valid_runtime->period_size); 76726c53379STimo Wischer /* The same timer interrupt is used for playback and capture device */ 76826c53379STimo Wischer if ((running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) && 76926c53379STimo Wischer (running & (1 << SNDRV_PCM_STREAM_CAPTURE))) { 77026c53379STimo Wischer copy_play_buf(dpcm_play, dpcm_capt, elapsed_bytes); 77126c53379STimo Wischer bytepos_finish(dpcm_play, elapsed_bytes); 77226c53379STimo Wischer bytepos_finish(dpcm_capt, elapsed_bytes); 77326c53379STimo Wischer } else if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { 77426c53379STimo Wischer bytepos_finish(dpcm_play, elapsed_bytes); 77526c53379STimo Wischer } else if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) { 77626c53379STimo Wischer clear_capture_buf(dpcm_capt, elapsed_bytes); 77726c53379STimo Wischer bytepos_finish(dpcm_capt, elapsed_bytes); 77826c53379STimo Wischer } 77926c53379STimo Wischer spin_unlock_irqrestore(&cable->lock, flags); 78026c53379STimo Wischer 78126c53379STimo Wischer if (substream_play) 78226c53379STimo Wischer snd_pcm_period_elapsed(substream_play); 78326c53379STimo Wischer if (substream_capt) 78426c53379STimo Wischer snd_pcm_period_elapsed(substream_capt); 78526c53379STimo Wischer } 78626c53379STimo Wischer 78726c53379STimo Wischer static void loopback_snd_timer_function(struct snd_timer_instance *timeri, 78826c53379STimo Wischer unsigned long resolution, 78926c53379STimo Wischer unsigned long ticks) 79026c53379STimo Wischer { 79126c53379STimo Wischer struct loopback_cable *cable = timeri->callback_data; 79226c53379STimo Wischer 79326c53379STimo Wischer loopback_snd_timer_period_elapsed(cable, SNDRV_TIMER_EVENT_TICK, 79426c53379STimo Wischer resolution); 79526c53379STimo Wischer } 79626c53379STimo Wischer 79726c53379STimo Wischer static void loopback_snd_timer_tasklet(unsigned long arg) 79826c53379STimo Wischer { 79926c53379STimo Wischer struct snd_timer_instance *timeri = (struct snd_timer_instance *)arg; 80026c53379STimo Wischer struct loopback_cable *cable = timeri->callback_data; 80126c53379STimo Wischer 80226c53379STimo Wischer loopback_snd_timer_period_elapsed(cable, SNDRV_TIMER_EVENT_MSTOP, 0); 80326c53379STimo Wischer } 80426c53379STimo Wischer 80526c53379STimo Wischer static void loopback_snd_timer_event(struct snd_timer_instance *timeri, 80626c53379STimo Wischer int event, 807fcae40c9SBaolin Wang struct timespec64 *tstamp, 80826c53379STimo Wischer unsigned long resolution) 80926c53379STimo Wischer { 81026c53379STimo Wischer /* Do not lock cable->lock here because timer->lock is already hold. 81126c53379STimo Wischer * There are other functions which first lock cable->lock and than 81226c53379STimo Wischer * timer->lock e.g. 81326c53379STimo Wischer * loopback_trigger() 81426c53379STimo Wischer * spin_lock(&cable->lock) 81526c53379STimo Wischer * loopback_snd_timer_start() 81626c53379STimo Wischer * snd_timer_start() 81726c53379STimo Wischer * spin_lock(&timer->lock) 81826c53379STimo Wischer * Therefore when using the oposit order of locks here it could result 81926c53379STimo Wischer * in a deadlock. 82026c53379STimo Wischer */ 82126c53379STimo Wischer 82226c53379STimo Wischer if (event == SNDRV_TIMER_EVENT_MSTOP) { 82326c53379STimo Wischer struct loopback_cable *cable = timeri->callback_data; 82426c53379STimo Wischer 82526c53379STimo Wischer /* sound card of the timer was stopped. Therefore there will not 82626c53379STimo Wischer * be any further timer callbacks. Due to this forward audio 82726c53379STimo Wischer * data from here if in draining state. When still in running 82826c53379STimo Wischer * state the streaming will be aborted by the usual timeout. It 82926c53379STimo Wischer * should not be aborted here because may be the timer sound 83026c53379STimo Wischer * card does only a recovery and the timer is back soon. 83126c53379STimo Wischer * This tasklet triggers loopback_snd_timer_tasklet() 83226c53379STimo Wischer */ 83326c53379STimo Wischer tasklet_schedule(&cable->snd_timer.event_tasklet); 83426c53379STimo Wischer } 83526c53379STimo Wischer } 83626c53379STimo Wischer 837133f3759STimo Wischer static void loopback_jiffies_timer_dpcm_info(struct loopback_pcm *dpcm, 838133f3759STimo Wischer struct snd_info_buffer *buffer) 839133f3759STimo Wischer { 840133f3759STimo Wischer snd_iprintf(buffer, " update_pending:\t%u\n", 841133f3759STimo Wischer dpcm->period_update_pending); 842133f3759STimo Wischer snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos); 843133f3759STimo Wischer snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac); 844133f3759STimo Wischer snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n", 845133f3759STimo Wischer dpcm->last_jiffies, jiffies); 846133f3759STimo Wischer snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires); 847133f3759STimo Wischer } 848133f3759STimo Wischer 84926c53379STimo Wischer static void loopback_snd_timer_dpcm_info(struct loopback_pcm *dpcm, 85026c53379STimo Wischer struct snd_info_buffer *buffer) 85126c53379STimo Wischer { 85226c53379STimo Wischer struct loopback_cable *cable = dpcm->cable; 85326c53379STimo Wischer 85426c53379STimo Wischer snd_iprintf(buffer, " sound timer:\thw:%d,%d,%d\n", 85526c53379STimo Wischer cable->snd_timer.id.card, 85626c53379STimo Wischer cable->snd_timer.id.device, 85726c53379STimo Wischer cable->snd_timer.id.subdevice); 85826c53379STimo Wischer snd_iprintf(buffer, " timer open:\t\t%s\n", 85926c53379STimo Wischer (cable->snd_timer.stream == SNDRV_PCM_STREAM_CAPTURE) ? 86026c53379STimo Wischer "capture" : "playback"); 86126c53379STimo Wischer } 86226c53379STimo Wischer 863597603d6SJaroslav Kysela static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) 864597603d6SJaroslav Kysela { 865597603d6SJaroslav Kysela struct snd_pcm_runtime *runtime = substream->runtime; 866597603d6SJaroslav Kysela struct loopback_pcm *dpcm = runtime->private_data; 867999fc9f6STakashi Iwai snd_pcm_uframes_t pos; 868597603d6SJaroslav Kysela 869999fc9f6STakashi Iwai spin_lock(&dpcm->cable->lock); 870133f3759STimo Wischer if (dpcm->cable->ops->pos_update) 871133f3759STimo Wischer dpcm->cable->ops->pos_update(dpcm->cable); 872999fc9f6STakashi Iwai pos = dpcm->buf_pos; 873999fc9f6STakashi Iwai spin_unlock(&dpcm->cable->lock); 874999fc9f6STakashi Iwai return bytes_to_frames(runtime, pos); 875597603d6SJaroslav Kysela } 876597603d6SJaroslav Kysela 877b6c0b715SBhumika Goyal static const struct snd_pcm_hardware loopback_pcm_hardware = 878597603d6SJaroslav Kysela { 879597603d6SJaroslav Kysela .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | 880edac8943STakashi Iwai SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | 881edac8943STakashi Iwai SNDRV_PCM_INFO_RESUME), 882597603d6SJaroslav Kysela .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | 88350e09084STimo Wischer SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | 88450e09084STimo Wischer SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | 885597603d6SJaroslav Kysela SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | 886597603d6SJaroslav Kysela SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE), 887597603d6SJaroslav Kysela .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000, 888597603d6SJaroslav Kysela .rate_min = 8000, 889597603d6SJaroslav Kysela .rate_max = 192000, 890597603d6SJaroslav Kysela .channels_min = 1, 891597603d6SJaroslav Kysela .channels_max = 32, 892597603d6SJaroslav Kysela .buffer_bytes_max = 2 * 1024 * 1024, 893597603d6SJaroslav Kysela .period_bytes_min = 64, 8940db71023SJaroslav Kysela /* note check overflow in frac_pos() using pcm_rate_shift before 8950db71023SJaroslav Kysela changing period_bytes_max value */ 8960db71023SJaroslav Kysela .period_bytes_max = 1024 * 1024, 897597603d6SJaroslav Kysela .periods_min = 1, 898597603d6SJaroslav Kysela .periods_max = 1024, 899597603d6SJaroslav Kysela .fifo_size = 0, 900597603d6SJaroslav Kysela }; 901597603d6SJaroslav Kysela 902597603d6SJaroslav Kysela static void loopback_runtime_free(struct snd_pcm_runtime *runtime) 903597603d6SJaroslav Kysela { 904597603d6SJaroslav Kysela struct loopback_pcm *dpcm = runtime->private_data; 905597603d6SJaroslav Kysela kfree(dpcm); 906597603d6SJaroslav Kysela } 907597603d6SJaroslav Kysela 908597603d6SJaroslav Kysela static int loopback_hw_params(struct snd_pcm_substream *substream, 909597603d6SJaroslav Kysela struct snd_pcm_hw_params *params) 910597603d6SJaroslav Kysela { 911b29e5ef1STakashi Iwai return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); 912597603d6SJaroslav Kysela } 913597603d6SJaroslav Kysela 914597603d6SJaroslav Kysela static int loopback_hw_free(struct snd_pcm_substream *substream) 915597603d6SJaroslav Kysela { 916597603d6SJaroslav Kysela struct snd_pcm_runtime *runtime = substream->runtime; 917597603d6SJaroslav Kysela struct loopback_pcm *dpcm = runtime->private_data; 918597603d6SJaroslav Kysela struct loopback_cable *cable = dpcm->cable; 919597603d6SJaroslav Kysela 920597603d6SJaroslav Kysela mutex_lock(&dpcm->loopback->cable_lock); 921597603d6SJaroslav Kysela cable->valid &= ~(1 << substream->stream); 922597603d6SJaroslav Kysela mutex_unlock(&dpcm->loopback->cable_lock); 923b29e5ef1STakashi Iwai return snd_pcm_lib_free_pages(substream); 924597603d6SJaroslav Kysela } 925597603d6SJaroslav Kysela 926597603d6SJaroslav Kysela static unsigned int get_cable_index(struct snd_pcm_substream *substream) 927597603d6SJaroslav Kysela { 928597603d6SJaroslav Kysela if (!substream->pcm->device) 929597603d6SJaroslav Kysela return substream->stream; 930597603d6SJaroslav Kysela else 931597603d6SJaroslav Kysela return !substream->stream; 932597603d6SJaroslav Kysela } 933597603d6SJaroslav Kysela 934b1c73fc8SJaroslav Kysela static int rule_format(struct snd_pcm_hw_params *params, 935b1c73fc8SJaroslav Kysela struct snd_pcm_hw_rule *rule) 936b1c73fc8SJaroslav Kysela { 937898dfe46STakashi Iwai struct loopback_pcm *dpcm = rule->private; 938898dfe46STakashi Iwai struct loopback_cable *cable = dpcm->cable; 939b088b53eSTakashi Iwai struct snd_mask m; 940b1c73fc8SJaroslav Kysela 941b088b53eSTakashi Iwai snd_mask_none(&m); 942898dfe46STakashi Iwai mutex_lock(&dpcm->loopback->cable_lock); 943898dfe46STakashi Iwai m.bits[0] = (u_int32_t)cable->hw.formats; 944898dfe46STakashi Iwai m.bits[1] = (u_int32_t)(cable->hw.formats >> 32); 945898dfe46STakashi Iwai mutex_unlock(&dpcm->loopback->cable_lock); 946b088b53eSTakashi Iwai return snd_mask_refine(hw_param_mask(params, rule->var), &m); 947b1c73fc8SJaroslav Kysela } 948b1c73fc8SJaroslav Kysela 949b1c73fc8SJaroslav Kysela static int rule_rate(struct snd_pcm_hw_params *params, 950b1c73fc8SJaroslav Kysela struct snd_pcm_hw_rule *rule) 951b1c73fc8SJaroslav Kysela { 952898dfe46STakashi Iwai struct loopback_pcm *dpcm = rule->private; 953898dfe46STakashi Iwai struct loopback_cable *cable = dpcm->cable; 954b1c73fc8SJaroslav Kysela struct snd_interval t; 955b1c73fc8SJaroslav Kysela 956898dfe46STakashi Iwai mutex_lock(&dpcm->loopback->cable_lock); 957898dfe46STakashi Iwai t.min = cable->hw.rate_min; 958898dfe46STakashi Iwai t.max = cable->hw.rate_max; 959898dfe46STakashi Iwai mutex_unlock(&dpcm->loopback->cable_lock); 960b1c73fc8SJaroslav Kysela t.openmin = t.openmax = 0; 961b1c73fc8SJaroslav Kysela t.integer = 0; 962b1c73fc8SJaroslav Kysela return snd_interval_refine(hw_param_interval(params, rule->var), &t); 963b1c73fc8SJaroslav Kysela } 964b1c73fc8SJaroslav Kysela 965b1c73fc8SJaroslav Kysela static int rule_channels(struct snd_pcm_hw_params *params, 966b1c73fc8SJaroslav Kysela struct snd_pcm_hw_rule *rule) 967b1c73fc8SJaroslav Kysela { 968898dfe46STakashi Iwai struct loopback_pcm *dpcm = rule->private; 969898dfe46STakashi Iwai struct loopback_cable *cable = dpcm->cable; 970b1c73fc8SJaroslav Kysela struct snd_interval t; 971b1c73fc8SJaroslav Kysela 972898dfe46STakashi Iwai mutex_lock(&dpcm->loopback->cable_lock); 973898dfe46STakashi Iwai t.min = cable->hw.channels_min; 974898dfe46STakashi Iwai t.max = cable->hw.channels_max; 975898dfe46STakashi Iwai mutex_unlock(&dpcm->loopback->cable_lock); 976b1c73fc8SJaroslav Kysela t.openmin = t.openmax = 0; 977b1c73fc8SJaroslav Kysela t.integer = 0; 978b1c73fc8SJaroslav Kysela return snd_interval_refine(hw_param_interval(params, rule->var), &t); 979b1c73fc8SJaroslav Kysela } 980b1c73fc8SJaroslav Kysela 98126c53379STimo Wischer static int rule_period_bytes(struct snd_pcm_hw_params *params, 98226c53379STimo Wischer struct snd_pcm_hw_rule *rule) 98326c53379STimo Wischer { 98426c53379STimo Wischer struct loopback_pcm *dpcm = rule->private; 98526c53379STimo Wischer struct loopback_cable *cable = dpcm->cable; 98626c53379STimo Wischer struct snd_interval t; 98726c53379STimo Wischer 98826c53379STimo Wischer mutex_lock(&dpcm->loopback->cable_lock); 98926c53379STimo Wischer t.min = cable->hw.period_bytes_min; 99026c53379STimo Wischer t.max = cable->hw.period_bytes_max; 99126c53379STimo Wischer mutex_unlock(&dpcm->loopback->cable_lock); 99226c53379STimo Wischer t.openmin = 0; 99326c53379STimo Wischer t.openmax = 0; 99426c53379STimo Wischer t.integer = 0; 99526c53379STimo Wischer return snd_interval_refine(hw_param_interval(params, rule->var), &t); 99626c53379STimo Wischer } 99726c53379STimo Wischer 9989685347aSTakashi Iwai static void free_cable(struct snd_pcm_substream *substream) 9999685347aSTakashi Iwai { 10009685347aSTakashi Iwai struct loopback *loopback = substream->private_data; 10019685347aSTakashi Iwai int dev = get_cable_index(substream); 10029685347aSTakashi Iwai struct loopback_cable *cable; 10039685347aSTakashi Iwai 10049685347aSTakashi Iwai cable = loopback->cables[substream->number][dev]; 10059685347aSTakashi Iwai if (!cable) 10069685347aSTakashi Iwai return; 10079685347aSTakashi Iwai if (cable->streams[!substream->stream]) { 10089685347aSTakashi Iwai /* other stream is still alive */ 10098e6b1a72STakashi Iwai spin_lock_irq(&cable->lock); 10109685347aSTakashi Iwai cable->streams[substream->stream] = NULL; 10118e6b1a72STakashi Iwai spin_unlock_irq(&cable->lock); 10129685347aSTakashi Iwai } else { 1013133f3759STimo Wischer struct loopback_pcm *dpcm = substream->runtime->private_data; 1014133f3759STimo Wischer 1015133f3759STimo Wischer if (cable->ops && cable->ops->close_cable && dpcm) 1016133f3759STimo Wischer cable->ops->close_cable(dpcm); 10179685347aSTakashi Iwai /* free the cable */ 10189685347aSTakashi Iwai loopback->cables[substream->number][dev] = NULL; 10199685347aSTakashi Iwai kfree(cable); 10209685347aSTakashi Iwai } 10219685347aSTakashi Iwai } 10229685347aSTakashi Iwai 1023133f3759STimo Wischer static int loopback_jiffies_timer_open(struct loopback_pcm *dpcm) 1024133f3759STimo Wischer { 10258e3bf7cdSTimo Wischer timer_setup(&dpcm->timer, loopback_jiffies_timer_function, 0); 1026133f3759STimo Wischer 1027133f3759STimo Wischer return 0; 1028133f3759STimo Wischer } 1029133f3759STimo Wischer 1030133f3759STimo Wischer static struct loopback_ops loopback_jiffies_timer_ops = { 1031133f3759STimo Wischer .open = loopback_jiffies_timer_open, 10328e3bf7cdSTimo Wischer .start = loopback_jiffies_timer_start, 10338e3bf7cdSTimo Wischer .stop = loopback_jiffies_timer_stop, 10348e3bf7cdSTimo Wischer .stop_sync = loopback_jiffies_timer_stop_sync, 10358e3bf7cdSTimo Wischer .close_substream = loopback_jiffies_timer_stop_sync, 10368e3bf7cdSTimo Wischer .pos_update = loopback_jiffies_timer_pos_update, 1037133f3759STimo Wischer .dpcm_info = loopback_jiffies_timer_dpcm_info, 1038133f3759STimo Wischer }; 1039133f3759STimo Wischer 104026c53379STimo Wischer static int loopback_parse_timer_id(const char *str, 104126c53379STimo Wischer struct snd_timer_id *tid) 104226c53379STimo Wischer { 104326c53379STimo Wischer /* [<pref>:](<card name>|<card idx>)[{.,}<dev idx>[{.,}<subdev idx>]] */ 104426c53379STimo Wischer const char * const sep_dev = ".,"; 104526c53379STimo Wischer const char * const sep_pref = ":"; 104626c53379STimo Wischer const char *name = str; 104726c53379STimo Wischer char *sep, save = '\0'; 104826c53379STimo Wischer int card_idx = 0, dev = 0, subdev = 0; 104926c53379STimo Wischer int err; 105026c53379STimo Wischer 105126c53379STimo Wischer sep = strpbrk(str, sep_pref); 105226c53379STimo Wischer if (sep) 105326c53379STimo Wischer name = sep + 1; 105426c53379STimo Wischer sep = strpbrk(name, sep_dev); 105526c53379STimo Wischer if (sep) { 105626c53379STimo Wischer save = *sep; 105726c53379STimo Wischer *sep = '\0'; 105826c53379STimo Wischer } 105926c53379STimo Wischer err = kstrtoint(name, 0, &card_idx); 106026c53379STimo Wischer if (err == -EINVAL) { 106126c53379STimo Wischer /* Must be the name, not number */ 106226c53379STimo Wischer for (card_idx = 0; card_idx < snd_ecards_limit; card_idx++) { 106326c53379STimo Wischer struct snd_card *card = snd_card_ref(card_idx); 106426c53379STimo Wischer 106526c53379STimo Wischer if (card) { 106626c53379STimo Wischer if (!strcmp(card->id, name)) 106726c53379STimo Wischer err = 0; 106826c53379STimo Wischer snd_card_unref(card); 106926c53379STimo Wischer } 107026c53379STimo Wischer if (!err) 107126c53379STimo Wischer break; 107226c53379STimo Wischer } 107326c53379STimo Wischer } 107426c53379STimo Wischer if (sep) { 107526c53379STimo Wischer *sep = save; 107626c53379STimo Wischer if (!err) { 107726c53379STimo Wischer char *sep2, save2 = '\0'; 107826c53379STimo Wischer 107926c53379STimo Wischer sep2 = strpbrk(sep + 1, sep_dev); 108026c53379STimo Wischer if (sep2) { 108126c53379STimo Wischer save2 = *sep2; 108226c53379STimo Wischer *sep2 = '\0'; 108326c53379STimo Wischer } 108426c53379STimo Wischer err = kstrtoint(sep + 1, 0, &dev); 108526c53379STimo Wischer if (sep2) { 108626c53379STimo Wischer *sep2 = save2; 108726c53379STimo Wischer if (!err) 108826c53379STimo Wischer err = kstrtoint(sep2 + 1, 0, &subdev); 108926c53379STimo Wischer } 109026c53379STimo Wischer } 109126c53379STimo Wischer } 109226c53379STimo Wischer if (!err && tid) { 109326c53379STimo Wischer tid->card = card_idx; 109426c53379STimo Wischer tid->device = dev; 109526c53379STimo Wischer tid->subdevice = subdev; 109626c53379STimo Wischer } 109726c53379STimo Wischer return err; 109826c53379STimo Wischer } 109926c53379STimo Wischer 110026c53379STimo Wischer /* call in loopback->cable_lock */ 110126c53379STimo Wischer static int loopback_snd_timer_open(struct loopback_pcm *dpcm) 110226c53379STimo Wischer { 110326c53379STimo Wischer int err = 0; 110426c53379STimo Wischer struct snd_timer_id tid = { 110526c53379STimo Wischer .dev_class = SNDRV_TIMER_CLASS_PCM, 110626c53379STimo Wischer .dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION, 110726c53379STimo Wischer }; 110826c53379STimo Wischer struct snd_timer_instance *timeri; 110926c53379STimo Wischer struct loopback_cable *cable = dpcm->cable; 111026c53379STimo Wischer 111126c53379STimo Wischer /* check if timer was already opened. It is only opened once 111226c53379STimo Wischer * per playback and capture subdevice (aka cable). 111326c53379STimo Wischer */ 111426c53379STimo Wischer if (cable->snd_timer.instance) 1115c037239cSAndrew Gabbasov goto exit; 111626c53379STimo Wischer 111726c53379STimo Wischer err = loopback_parse_timer_id(dpcm->loopback->timer_source, &tid); 111826c53379STimo Wischer if (err < 0) { 111926c53379STimo Wischer pcm_err(dpcm->substream->pcm, 112026c53379STimo Wischer "Parsing timer source \'%s\' failed with %d", 112126c53379STimo Wischer dpcm->loopback->timer_source, err); 1122c037239cSAndrew Gabbasov goto exit; 112326c53379STimo Wischer } 112426c53379STimo Wischer 112526c53379STimo Wischer cable->snd_timer.stream = dpcm->substream->stream; 112626c53379STimo Wischer cable->snd_timer.id = tid; 112726c53379STimo Wischer 112826c53379STimo Wischer timeri = snd_timer_instance_new(dpcm->loopback->card->id); 112926c53379STimo Wischer if (!timeri) { 113026c53379STimo Wischer err = -ENOMEM; 1131c037239cSAndrew Gabbasov goto exit; 113226c53379STimo Wischer } 113326c53379STimo Wischer /* The callback has to be called from another tasklet. If 113426c53379STimo Wischer * SNDRV_TIMER_IFLG_FAST is specified it will be called from the 113526c53379STimo Wischer * snd_pcm_period_elapsed() call of the selected sound card. 113626c53379STimo Wischer * snd_pcm_period_elapsed() helds snd_pcm_stream_lock_irqsave(). 113726c53379STimo Wischer * Due to our callback loopback_snd_timer_function() also calls 113826c53379STimo Wischer * snd_pcm_period_elapsed() which calls snd_pcm_stream_lock_irqsave(). 113926c53379STimo Wischer * This would end up in a dead lock. 114026c53379STimo Wischer */ 114126c53379STimo Wischer timeri->flags |= SNDRV_TIMER_IFLG_AUTO; 114226c53379STimo Wischer timeri->callback = loopback_snd_timer_function; 114326c53379STimo Wischer timeri->callback_data = (void *)cable; 114426c53379STimo Wischer timeri->ccallback = loopback_snd_timer_event; 114526c53379STimo Wischer 114626c53379STimo Wischer /* initialise a tasklet used for draining */ 114726c53379STimo Wischer tasklet_init(&cable->snd_timer.event_tasklet, 114826c53379STimo Wischer loopback_snd_timer_tasklet, (unsigned long)timeri); 114926c53379STimo Wischer 1150c037239cSAndrew Gabbasov /* The mutex loopback->cable_lock is kept locked. 1151c037239cSAndrew Gabbasov * Therefore snd_timer_open() cannot be called a second time 1152c037239cSAndrew Gabbasov * by the other device of the same cable. 115326c53379STimo Wischer * Therefore the following issue cannot happen: 115426c53379STimo Wischer * [proc1] Call loopback_timer_open() -> 115526c53379STimo Wischer * Unlock cable->lock for snd_timer_close/open() call 115626c53379STimo Wischer * [proc2] Call loopback_timer_open() -> snd_timer_open(), 115726c53379STimo Wischer * snd_timer_start() 115826c53379STimo Wischer * [proc1] Call snd_timer_open() and overwrite running timer 115926c53379STimo Wischer * instance 116026c53379STimo Wischer */ 116126c53379STimo Wischer err = snd_timer_open(timeri, &cable->snd_timer.id, current->pid); 116226c53379STimo Wischer if (err < 0) { 116326c53379STimo Wischer pcm_err(dpcm->substream->pcm, 116426c53379STimo Wischer "snd_timer_open (%d,%d,%d) failed with %d", 116526c53379STimo Wischer cable->snd_timer.id.card, 116626c53379STimo Wischer cable->snd_timer.id.device, 116726c53379STimo Wischer cable->snd_timer.id.subdevice, 116826c53379STimo Wischer err); 116926c53379STimo Wischer snd_timer_instance_free(timeri); 1170c037239cSAndrew Gabbasov goto exit; 117126c53379STimo Wischer } 117226c53379STimo Wischer 117326c53379STimo Wischer cable->snd_timer.instance = timeri; 117426c53379STimo Wischer 1175c037239cSAndrew Gabbasov exit: 117626c53379STimo Wischer return err; 117726c53379STimo Wischer } 117826c53379STimo Wischer 117926c53379STimo Wischer /* stop_sync() is not required for sound timer because it does not need to be 118026c53379STimo Wischer * restarted in loopback_prepare() on Xrun recovery 118126c53379STimo Wischer */ 118226c53379STimo Wischer static struct loopback_ops loopback_snd_timer_ops = { 118326c53379STimo Wischer .open = loopback_snd_timer_open, 118426c53379STimo Wischer .start = loopback_snd_timer_start, 118526c53379STimo Wischer .stop = loopback_snd_timer_stop, 118626c53379STimo Wischer .close_cable = loopback_snd_timer_close_cable, 118726c53379STimo Wischer .dpcm_info = loopback_snd_timer_dpcm_info, 118826c53379STimo Wischer }; 118926c53379STimo Wischer 1190597603d6SJaroslav Kysela static int loopback_open(struct snd_pcm_substream *substream) 1191597603d6SJaroslav Kysela { 1192597603d6SJaroslav Kysela struct snd_pcm_runtime *runtime = substream->runtime; 1193597603d6SJaroslav Kysela struct loopback *loopback = substream->private_data; 1194597603d6SJaroslav Kysela struct loopback_pcm *dpcm; 11959685347aSTakashi Iwai struct loopback_cable *cable = NULL; 1196597603d6SJaroslav Kysela int err = 0; 1197597603d6SJaroslav Kysela int dev = get_cable_index(substream); 1198597603d6SJaroslav Kysela 1199597603d6SJaroslav Kysela mutex_lock(&loopback->cable_lock); 1200597603d6SJaroslav Kysela dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); 1201597603d6SJaroslav Kysela if (!dpcm) { 1202597603d6SJaroslav Kysela err = -ENOMEM; 1203597603d6SJaroslav Kysela goto unlock; 1204597603d6SJaroslav Kysela } 1205597603d6SJaroslav Kysela dpcm->loopback = loopback; 1206597603d6SJaroslav Kysela dpcm->substream = substream; 1207597603d6SJaroslav Kysela 1208597603d6SJaroslav Kysela cable = loopback->cables[substream->number][dev]; 1209597603d6SJaroslav Kysela if (!cable) { 1210597603d6SJaroslav Kysela cable = kzalloc(sizeof(*cable), GFP_KERNEL); 1211597603d6SJaroslav Kysela if (!cable) { 1212597603d6SJaroslav Kysela err = -ENOMEM; 1213597603d6SJaroslav Kysela goto unlock; 1214597603d6SJaroslav Kysela } 1215597603d6SJaroslav Kysela spin_lock_init(&cable->lock); 1216597603d6SJaroslav Kysela cable->hw = loopback_pcm_hardware; 121726c53379STimo Wischer if (loopback->timer_source) 121826c53379STimo Wischer cable->ops = &loopback_snd_timer_ops; 121926c53379STimo Wischer else 1220133f3759STimo Wischer cable->ops = &loopback_jiffies_timer_ops; 1221597603d6SJaroslav Kysela loopback->cables[substream->number][dev] = cable; 1222597603d6SJaroslav Kysela } 1223597603d6SJaroslav Kysela dpcm->cable = cable; 1224133f3759STimo Wischer runtime->private_data = dpcm; 1225133f3759STimo Wischer 1226133f3759STimo Wischer if (cable->ops->open) { 1227133f3759STimo Wischer err = cable->ops->open(dpcm); 1228133f3759STimo Wischer if (err < 0) 1229133f3759STimo Wischer goto unlock; 1230133f3759STimo Wischer } 1231597603d6SJaroslav Kysela 1232597603d6SJaroslav Kysela snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 1233597603d6SJaroslav Kysela 1234b1c73fc8SJaroslav Kysela /* use dynamic rules based on actual runtime->hw values */ 1235b1c73fc8SJaroslav Kysela /* note that the default rules created in the PCM midlevel code */ 1236b1c73fc8SJaroslav Kysela /* are cached -> they do not reflect the actual state */ 1237b1c73fc8SJaroslav Kysela err = snd_pcm_hw_rule_add(runtime, 0, 1238b1c73fc8SJaroslav Kysela SNDRV_PCM_HW_PARAM_FORMAT, 1239898dfe46STakashi Iwai rule_format, dpcm, 1240b1c73fc8SJaroslav Kysela SNDRV_PCM_HW_PARAM_FORMAT, -1); 1241b1c73fc8SJaroslav Kysela if (err < 0) 1242b1c73fc8SJaroslav Kysela goto unlock; 1243b1c73fc8SJaroslav Kysela err = snd_pcm_hw_rule_add(runtime, 0, 1244b1c73fc8SJaroslav Kysela SNDRV_PCM_HW_PARAM_RATE, 1245898dfe46STakashi Iwai rule_rate, dpcm, 1246b1c73fc8SJaroslav Kysela SNDRV_PCM_HW_PARAM_RATE, -1); 1247b1c73fc8SJaroslav Kysela if (err < 0) 1248b1c73fc8SJaroslav Kysela goto unlock; 1249b1c73fc8SJaroslav Kysela err = snd_pcm_hw_rule_add(runtime, 0, 1250b1c73fc8SJaroslav Kysela SNDRV_PCM_HW_PARAM_CHANNELS, 1251898dfe46STakashi Iwai rule_channels, dpcm, 1252b1c73fc8SJaroslav Kysela SNDRV_PCM_HW_PARAM_CHANNELS, -1); 1253b1c73fc8SJaroslav Kysela if (err < 0) 1254b1c73fc8SJaroslav Kysela goto unlock; 1255b1c73fc8SJaroslav Kysela 125626c53379STimo Wischer /* In case of sound timer the period time of both devices of the same 125726c53379STimo Wischer * loop has to be the same. 125826c53379STimo Wischer * This rule only takes effect if a sound timer was chosen 125926c53379STimo Wischer */ 126026c53379STimo Wischer if (cable->snd_timer.instance) { 126126c53379STimo Wischer err = snd_pcm_hw_rule_add(runtime, 0, 126226c53379STimo Wischer SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 126326c53379STimo Wischer rule_period_bytes, dpcm, 126426c53379STimo Wischer SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -1); 126526c53379STimo Wischer if (err < 0) 126626c53379STimo Wischer goto unlock; 126726c53379STimo Wischer } 126826c53379STimo Wischer 1269133f3759STimo Wischer /* loopback_runtime_free() has not to be called if kfree(dpcm) was 1270133f3759STimo Wischer * already called here. Otherwise it will end up with a double free. 1271133f3759STimo Wischer */ 1272597603d6SJaroslav Kysela runtime->private_free = loopback_runtime_free; 1273b1c73fc8SJaroslav Kysela if (get_notify(dpcm)) 1274597603d6SJaroslav Kysela runtime->hw = loopback_pcm_hardware; 1275b1c73fc8SJaroslav Kysela else 1276597603d6SJaroslav Kysela runtime->hw = cable->hw; 12778e6b1a72STakashi Iwai 12788e6b1a72STakashi Iwai spin_lock_irq(&cable->lock); 12798e6b1a72STakashi Iwai cable->streams[substream->stream] = dpcm; 12808e6b1a72STakashi Iwai spin_unlock_irq(&cable->lock); 12818e6b1a72STakashi Iwai 1282597603d6SJaroslav Kysela unlock: 12839685347aSTakashi Iwai if (err < 0) { 12849685347aSTakashi Iwai free_cable(substream); 12859685347aSTakashi Iwai kfree(dpcm); 12869685347aSTakashi Iwai } 1287597603d6SJaroslav Kysela mutex_unlock(&loopback->cable_lock); 1288597603d6SJaroslav Kysela return err; 1289597603d6SJaroslav Kysela } 1290597603d6SJaroslav Kysela 1291597603d6SJaroslav Kysela static int loopback_close(struct snd_pcm_substream *substream) 1292597603d6SJaroslav Kysela { 1293597603d6SJaroslav Kysela struct loopback *loopback = substream->private_data; 1294597603d6SJaroslav Kysela struct loopback_pcm *dpcm = substream->runtime->private_data; 1295133f3759STimo Wischer int err = 0; 1296597603d6SJaroslav Kysela 1297133f3759STimo Wischer if (dpcm->cable->ops->close_substream) 1298133f3759STimo Wischer err = dpcm->cable->ops->close_substream(dpcm); 1299597603d6SJaroslav Kysela mutex_lock(&loopback->cable_lock); 13009685347aSTakashi Iwai free_cable(substream); 1301597603d6SJaroslav Kysela mutex_unlock(&loopback->cable_lock); 1302133f3759STimo Wischer return err; 1303597603d6SJaroslav Kysela } 1304597603d6SJaroslav Kysela 13059f88058eSTakashi Iwai static const struct snd_pcm_ops loopback_pcm_ops = { 1306597603d6SJaroslav Kysela .open = loopback_open, 1307597603d6SJaroslav Kysela .close = loopback_close, 1308597603d6SJaroslav Kysela .ioctl = snd_pcm_lib_ioctl, 1309597603d6SJaroslav Kysela .hw_params = loopback_hw_params, 1310597603d6SJaroslav Kysela .hw_free = loopback_hw_free, 1311597603d6SJaroslav Kysela .prepare = loopback_prepare, 1312597603d6SJaroslav Kysela .trigger = loopback_trigger, 1313597603d6SJaroslav Kysela .pointer = loopback_pointer, 1314597603d6SJaroslav Kysela }; 1315597603d6SJaroslav Kysela 1316fbbb01a1SBill Pemberton static int loopback_pcm_new(struct loopback *loopback, 1317597603d6SJaroslav Kysela int device, int substreams) 1318597603d6SJaroslav Kysela { 1319597603d6SJaroslav Kysela struct snd_pcm *pcm; 1320597603d6SJaroslav Kysela int err; 1321597603d6SJaroslav Kysela 1322597603d6SJaroslav Kysela err = snd_pcm_new(loopback->card, "Loopback PCM", device, 1323597603d6SJaroslav Kysela substreams, substreams, &pcm); 1324597603d6SJaroslav Kysela if (err < 0) 1325597603d6SJaroslav Kysela return err; 13269f88058eSTakashi Iwai snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_pcm_ops); 13279f88058eSTakashi Iwai snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_pcm_ops); 1328b29e5ef1STakashi Iwai snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_VMALLOC, 1329b29e5ef1STakashi Iwai NULL, 0, 0); 1330597603d6SJaroslav Kysela 1331597603d6SJaroslav Kysela pcm->private_data = loopback; 1332597603d6SJaroslav Kysela pcm->info_flags = 0; 1333597603d6SJaroslav Kysela strcpy(pcm->name, "Loopback PCM"); 1334597603d6SJaroslav Kysela 1335597603d6SJaroslav Kysela loopback->pcm[device] = pcm; 1336597603d6SJaroslav Kysela return 0; 1337597603d6SJaroslav Kysela } 1338597603d6SJaroslav Kysela 1339597603d6SJaroslav Kysela static int loopback_rate_shift_info(struct snd_kcontrol *kcontrol, 1340597603d6SJaroslav Kysela struct snd_ctl_elem_info *uinfo) 1341597603d6SJaroslav Kysela { 1342597603d6SJaroslav Kysela uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 1343597603d6SJaroslav Kysela uinfo->count = 1; 1344597603d6SJaroslav Kysela uinfo->value.integer.min = 80000; 1345597603d6SJaroslav Kysela uinfo->value.integer.max = 120000; 1346597603d6SJaroslav Kysela uinfo->value.integer.step = 1; 1347597603d6SJaroslav Kysela return 0; 1348597603d6SJaroslav Kysela } 1349597603d6SJaroslav Kysela 1350597603d6SJaroslav Kysela static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol, 1351597603d6SJaroslav Kysela struct snd_ctl_elem_value *ucontrol) 1352597603d6SJaroslav Kysela { 1353597603d6SJaroslav Kysela struct loopback *loopback = snd_kcontrol_chip(kcontrol); 1354597603d6SJaroslav Kysela 135576b3421bSTakashi Iwai mutex_lock(&loopback->cable_lock); 1356597603d6SJaroslav Kysela ucontrol->value.integer.value[0] = 1357597603d6SJaroslav Kysela loopback->setup[kcontrol->id.subdevice] 1358597603d6SJaroslav Kysela [kcontrol->id.device].rate_shift; 135976b3421bSTakashi Iwai mutex_unlock(&loopback->cable_lock); 1360597603d6SJaroslav Kysela return 0; 1361597603d6SJaroslav Kysela } 1362597603d6SJaroslav Kysela 1363597603d6SJaroslav Kysela static int loopback_rate_shift_put(struct snd_kcontrol *kcontrol, 1364597603d6SJaroslav Kysela struct snd_ctl_elem_value *ucontrol) 1365597603d6SJaroslav Kysela { 1366597603d6SJaroslav Kysela struct loopback *loopback = snd_kcontrol_chip(kcontrol); 1367597603d6SJaroslav Kysela unsigned int val; 1368597603d6SJaroslav Kysela int change = 0; 1369597603d6SJaroslav Kysela 1370597603d6SJaroslav Kysela val = ucontrol->value.integer.value[0]; 1371597603d6SJaroslav Kysela if (val < 80000) 1372597603d6SJaroslav Kysela val = 80000; 1373597603d6SJaroslav Kysela if (val > 120000) 1374597603d6SJaroslav Kysela val = 120000; 1375597603d6SJaroslav Kysela mutex_lock(&loopback->cable_lock); 1376597603d6SJaroslav Kysela if (val != loopback->setup[kcontrol->id.subdevice] 1377597603d6SJaroslav Kysela [kcontrol->id.device].rate_shift) { 1378597603d6SJaroslav Kysela loopback->setup[kcontrol->id.subdevice] 1379597603d6SJaroslav Kysela [kcontrol->id.device].rate_shift = val; 1380597603d6SJaroslav Kysela change = 1; 1381597603d6SJaroslav Kysela } 1382597603d6SJaroslav Kysela mutex_unlock(&loopback->cable_lock); 1383597603d6SJaroslav Kysela return change; 1384597603d6SJaroslav Kysela } 1385597603d6SJaroslav Kysela 1386597603d6SJaroslav Kysela static int loopback_notify_get(struct snd_kcontrol *kcontrol, 1387597603d6SJaroslav Kysela struct snd_ctl_elem_value *ucontrol) 1388597603d6SJaroslav Kysela { 1389597603d6SJaroslav Kysela struct loopback *loopback = snd_kcontrol_chip(kcontrol); 1390597603d6SJaroslav Kysela 139176b3421bSTakashi Iwai mutex_lock(&loopback->cable_lock); 1392597603d6SJaroslav Kysela ucontrol->value.integer.value[0] = 1393597603d6SJaroslav Kysela loopback->setup[kcontrol->id.subdevice] 1394597603d6SJaroslav Kysela [kcontrol->id.device].notify; 139576b3421bSTakashi Iwai mutex_unlock(&loopback->cable_lock); 1396597603d6SJaroslav Kysela return 0; 1397597603d6SJaroslav Kysela } 1398597603d6SJaroslav Kysela 1399597603d6SJaroslav Kysela static int loopback_notify_put(struct snd_kcontrol *kcontrol, 1400597603d6SJaroslav Kysela struct snd_ctl_elem_value *ucontrol) 1401597603d6SJaroslav Kysela { 1402597603d6SJaroslav Kysela struct loopback *loopback = snd_kcontrol_chip(kcontrol); 1403597603d6SJaroslav Kysela unsigned int val; 1404597603d6SJaroslav Kysela int change = 0; 1405597603d6SJaroslav Kysela 1406597603d6SJaroslav Kysela val = ucontrol->value.integer.value[0] ? 1 : 0; 140776b3421bSTakashi Iwai mutex_lock(&loopback->cable_lock); 1408597603d6SJaroslav Kysela if (val != loopback->setup[kcontrol->id.subdevice] 1409597603d6SJaroslav Kysela [kcontrol->id.device].notify) { 1410597603d6SJaroslav Kysela loopback->setup[kcontrol->id.subdevice] 1411597603d6SJaroslav Kysela [kcontrol->id.device].notify = val; 1412597603d6SJaroslav Kysela change = 1; 1413597603d6SJaroslav Kysela } 141476b3421bSTakashi Iwai mutex_unlock(&loopback->cable_lock); 1415597603d6SJaroslav Kysela return change; 1416597603d6SJaroslav Kysela } 1417597603d6SJaroslav Kysela 1418597603d6SJaroslav Kysela static int loopback_active_get(struct snd_kcontrol *kcontrol, 1419597603d6SJaroslav Kysela struct snd_ctl_elem_value *ucontrol) 1420597603d6SJaroslav Kysela { 1421597603d6SJaroslav Kysela struct loopback *loopback = snd_kcontrol_chip(kcontrol); 142276b3421bSTakashi Iwai struct loopback_cable *cable; 142376b3421bSTakashi Iwai 1424597603d6SJaroslav Kysela unsigned int val = 0; 1425597603d6SJaroslav Kysela 142676b3421bSTakashi Iwai mutex_lock(&loopback->cable_lock); 142776b3421bSTakashi Iwai cable = loopback->cables[kcontrol->id.subdevice][kcontrol->id.device ^ 1]; 1428306a4f3cSRobert Rosengren if (cable != NULL) { 1429306a4f3cSRobert Rosengren unsigned int running = cable->running ^ cable->pause; 1430306a4f3cSRobert Rosengren 1431306a4f3cSRobert Rosengren val = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? 1 : 0; 1432306a4f3cSRobert Rosengren } 143376b3421bSTakashi Iwai mutex_unlock(&loopback->cable_lock); 1434597603d6SJaroslav Kysela ucontrol->value.integer.value[0] = val; 1435597603d6SJaroslav Kysela return 0; 1436597603d6SJaroslav Kysela } 1437597603d6SJaroslav Kysela 1438597603d6SJaroslav Kysela static int loopback_format_info(struct snd_kcontrol *kcontrol, 1439597603d6SJaroslav Kysela struct snd_ctl_elem_info *uinfo) 1440597603d6SJaroslav Kysela { 1441597603d6SJaroslav Kysela uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 1442597603d6SJaroslav Kysela uinfo->count = 1; 1443597603d6SJaroslav Kysela uinfo->value.integer.min = 0; 1444597603d6SJaroslav Kysela uinfo->value.integer.max = SNDRV_PCM_FORMAT_LAST; 1445597603d6SJaroslav Kysela uinfo->value.integer.step = 1; 1446597603d6SJaroslav Kysela return 0; 1447597603d6SJaroslav Kysela } 1448597603d6SJaroslav Kysela 1449597603d6SJaroslav Kysela static int loopback_format_get(struct snd_kcontrol *kcontrol, 1450597603d6SJaroslav Kysela struct snd_ctl_elem_value *ucontrol) 1451597603d6SJaroslav Kysela { 1452597603d6SJaroslav Kysela struct loopback *loopback = snd_kcontrol_chip(kcontrol); 1453597603d6SJaroslav Kysela 1454597603d6SJaroslav Kysela ucontrol->value.integer.value[0] = 1455597603d6SJaroslav Kysela loopback->setup[kcontrol->id.subdevice] 1456597603d6SJaroslav Kysela [kcontrol->id.device].format; 1457597603d6SJaroslav Kysela return 0; 1458597603d6SJaroslav Kysela } 1459597603d6SJaroslav Kysela 1460597603d6SJaroslav Kysela static int loopback_rate_info(struct snd_kcontrol *kcontrol, 1461597603d6SJaroslav Kysela struct snd_ctl_elem_info *uinfo) 1462597603d6SJaroslav Kysela { 1463597603d6SJaroslav Kysela uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 1464597603d6SJaroslav Kysela uinfo->count = 1; 1465597603d6SJaroslav Kysela uinfo->value.integer.min = 0; 1466597603d6SJaroslav Kysela uinfo->value.integer.max = 192000; 1467597603d6SJaroslav Kysela uinfo->value.integer.step = 1; 1468597603d6SJaroslav Kysela return 0; 1469597603d6SJaroslav Kysela } 1470597603d6SJaroslav Kysela 1471597603d6SJaroslav Kysela static int loopback_rate_get(struct snd_kcontrol *kcontrol, 1472597603d6SJaroslav Kysela struct snd_ctl_elem_value *ucontrol) 1473597603d6SJaroslav Kysela { 1474597603d6SJaroslav Kysela struct loopback *loopback = snd_kcontrol_chip(kcontrol); 1475597603d6SJaroslav Kysela 147676b3421bSTakashi Iwai mutex_lock(&loopback->cable_lock); 1477597603d6SJaroslav Kysela ucontrol->value.integer.value[0] = 1478597603d6SJaroslav Kysela loopback->setup[kcontrol->id.subdevice] 1479597603d6SJaroslav Kysela [kcontrol->id.device].rate; 148076b3421bSTakashi Iwai mutex_unlock(&loopback->cable_lock); 1481597603d6SJaroslav Kysela return 0; 1482597603d6SJaroslav Kysela } 1483597603d6SJaroslav Kysela 1484597603d6SJaroslav Kysela static int loopback_channels_info(struct snd_kcontrol *kcontrol, 1485597603d6SJaroslav Kysela struct snd_ctl_elem_info *uinfo) 1486597603d6SJaroslav Kysela { 1487597603d6SJaroslav Kysela uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 1488597603d6SJaroslav Kysela uinfo->count = 1; 1489597603d6SJaroslav Kysela uinfo->value.integer.min = 1; 1490597603d6SJaroslav Kysela uinfo->value.integer.max = 1024; 1491597603d6SJaroslav Kysela uinfo->value.integer.step = 1; 1492597603d6SJaroslav Kysela return 0; 1493597603d6SJaroslav Kysela } 1494597603d6SJaroslav Kysela 1495597603d6SJaroslav Kysela static int loopback_channels_get(struct snd_kcontrol *kcontrol, 1496597603d6SJaroslav Kysela struct snd_ctl_elem_value *ucontrol) 1497597603d6SJaroslav Kysela { 1498597603d6SJaroslav Kysela struct loopback *loopback = snd_kcontrol_chip(kcontrol); 1499597603d6SJaroslav Kysela 150076b3421bSTakashi Iwai mutex_lock(&loopback->cable_lock); 1501597603d6SJaroslav Kysela ucontrol->value.integer.value[0] = 1502597603d6SJaroslav Kysela loopback->setup[kcontrol->id.subdevice] 15031446c5fbSJaroslav Kysela [kcontrol->id.device].channels; 150476b3421bSTakashi Iwai mutex_unlock(&loopback->cable_lock); 1505597603d6SJaroslav Kysela return 0; 1506597603d6SJaroslav Kysela } 1507597603d6SJaroslav Kysela 1508fbbb01a1SBill Pemberton static struct snd_kcontrol_new loopback_controls[] = { 1509597603d6SJaroslav Kysela { 1510597603d6SJaroslav Kysela .iface = SNDRV_CTL_ELEM_IFACE_PCM, 1511597603d6SJaroslav Kysela .name = "PCM Rate Shift 100000", 1512597603d6SJaroslav Kysela .info = loopback_rate_shift_info, 1513597603d6SJaroslav Kysela .get = loopback_rate_shift_get, 1514597603d6SJaroslav Kysela .put = loopback_rate_shift_put, 1515597603d6SJaroslav Kysela }, 1516597603d6SJaroslav Kysela { 1517597603d6SJaroslav Kysela .iface = SNDRV_CTL_ELEM_IFACE_PCM, 1518597603d6SJaroslav Kysela .name = "PCM Notify", 1519597603d6SJaroslav Kysela .info = snd_ctl_boolean_mono_info, 1520597603d6SJaroslav Kysela .get = loopback_notify_get, 1521597603d6SJaroslav Kysela .put = loopback_notify_put, 1522597603d6SJaroslav Kysela }, 1523597603d6SJaroslav Kysela #define ACTIVE_IDX 2 1524597603d6SJaroslav Kysela { 1525597603d6SJaroslav Kysela .access = SNDRV_CTL_ELEM_ACCESS_READ, 1526597603d6SJaroslav Kysela .iface = SNDRV_CTL_ELEM_IFACE_PCM, 1527597603d6SJaroslav Kysela .name = "PCM Slave Active", 1528597603d6SJaroslav Kysela .info = snd_ctl_boolean_mono_info, 1529597603d6SJaroslav Kysela .get = loopback_active_get, 1530597603d6SJaroslav Kysela }, 1531597603d6SJaroslav Kysela #define FORMAT_IDX 3 1532597603d6SJaroslav Kysela { 1533597603d6SJaroslav Kysela .access = SNDRV_CTL_ELEM_ACCESS_READ, 1534597603d6SJaroslav Kysela .iface = SNDRV_CTL_ELEM_IFACE_PCM, 1535597603d6SJaroslav Kysela .name = "PCM Slave Format", 1536597603d6SJaroslav Kysela .info = loopback_format_info, 1537597603d6SJaroslav Kysela .get = loopback_format_get 1538597603d6SJaroslav Kysela }, 1539597603d6SJaroslav Kysela #define RATE_IDX 4 1540597603d6SJaroslav Kysela { 1541597603d6SJaroslav Kysela .access = SNDRV_CTL_ELEM_ACCESS_READ, 1542597603d6SJaroslav Kysela .iface = SNDRV_CTL_ELEM_IFACE_PCM, 1543597603d6SJaroslav Kysela .name = "PCM Slave Rate", 1544597603d6SJaroslav Kysela .info = loopback_rate_info, 1545597603d6SJaroslav Kysela .get = loopback_rate_get 1546597603d6SJaroslav Kysela }, 1547597603d6SJaroslav Kysela #define CHANNELS_IDX 5 1548597603d6SJaroslav Kysela { 1549597603d6SJaroslav Kysela .access = SNDRV_CTL_ELEM_ACCESS_READ, 1550597603d6SJaroslav Kysela .iface = SNDRV_CTL_ELEM_IFACE_PCM, 1551597603d6SJaroslav Kysela .name = "PCM Slave Channels", 1552597603d6SJaroslav Kysela .info = loopback_channels_info, 1553597603d6SJaroslav Kysela .get = loopback_channels_get 1554597603d6SJaroslav Kysela } 1555597603d6SJaroslav Kysela }; 1556597603d6SJaroslav Kysela 1557fbbb01a1SBill Pemberton static int loopback_mixer_new(struct loopback *loopback, int notify) 1558597603d6SJaroslav Kysela { 1559597603d6SJaroslav Kysela struct snd_card *card = loopback->card; 1560597603d6SJaroslav Kysela struct snd_pcm *pcm; 1561597603d6SJaroslav Kysela struct snd_kcontrol *kctl; 1562597603d6SJaroslav Kysela struct loopback_setup *setup; 1563597603d6SJaroslav Kysela int err, dev, substr, substr_count, idx; 1564597603d6SJaroslav Kysela 1565597603d6SJaroslav Kysela strcpy(card->mixername, "Loopback Mixer"); 1566597603d6SJaroslav Kysela for (dev = 0; dev < 2; dev++) { 1567597603d6SJaroslav Kysela pcm = loopback->pcm[dev]; 1568597603d6SJaroslav Kysela substr_count = 1569597603d6SJaroslav Kysela pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count; 1570597603d6SJaroslav Kysela for (substr = 0; substr < substr_count; substr++) { 1571597603d6SJaroslav Kysela setup = &loopback->setup[substr][dev]; 1572597603d6SJaroslav Kysela setup->notify = notify; 1573597603d6SJaroslav Kysela setup->rate_shift = NO_PITCH; 1574597603d6SJaroslav Kysela setup->format = SNDRV_PCM_FORMAT_S16_LE; 1575597603d6SJaroslav Kysela setup->rate = 48000; 1576597603d6SJaroslav Kysela setup->channels = 2; 1577597603d6SJaroslav Kysela for (idx = 0; idx < ARRAY_SIZE(loopback_controls); 1578597603d6SJaroslav Kysela idx++) { 1579597603d6SJaroslav Kysela kctl = snd_ctl_new1(&loopback_controls[idx], 1580597603d6SJaroslav Kysela loopback); 1581597603d6SJaroslav Kysela if (!kctl) 1582597603d6SJaroslav Kysela return -ENOMEM; 1583597603d6SJaroslav Kysela kctl->id.device = dev; 1584597603d6SJaroslav Kysela kctl->id.subdevice = substr; 1585597603d6SJaroslav Kysela switch (idx) { 1586597603d6SJaroslav Kysela case ACTIVE_IDX: 1587597603d6SJaroslav Kysela setup->active_id = kctl->id; 1588597603d6SJaroslav Kysela break; 1589597603d6SJaroslav Kysela case FORMAT_IDX: 1590597603d6SJaroslav Kysela setup->format_id = kctl->id; 1591597603d6SJaroslav Kysela break; 1592597603d6SJaroslav Kysela case RATE_IDX: 1593597603d6SJaroslav Kysela setup->rate_id = kctl->id; 1594597603d6SJaroslav Kysela break; 1595597603d6SJaroslav Kysela case CHANNELS_IDX: 1596597603d6SJaroslav Kysela setup->channels_id = kctl->id; 1597597603d6SJaroslav Kysela break; 1598597603d6SJaroslav Kysela default: 1599597603d6SJaroslav Kysela break; 1600597603d6SJaroslav Kysela } 1601597603d6SJaroslav Kysela err = snd_ctl_add(card, kctl); 1602597603d6SJaroslav Kysela if (err < 0) 1603597603d6SJaroslav Kysela return err; 1604597603d6SJaroslav Kysela } 1605597603d6SJaroslav Kysela } 1606597603d6SJaroslav Kysela } 1607597603d6SJaroslav Kysela return 0; 1608597603d6SJaroslav Kysela } 1609597603d6SJaroslav Kysela 1610e74670b6SJaroslav Kysela static void print_dpcm_info(struct snd_info_buffer *buffer, 1611e74670b6SJaroslav Kysela struct loopback_pcm *dpcm, 1612e74670b6SJaroslav Kysela const char *id) 1613e74670b6SJaroslav Kysela { 1614e74670b6SJaroslav Kysela snd_iprintf(buffer, " %s\n", id); 1615e74670b6SJaroslav Kysela if (dpcm == NULL) { 1616e74670b6SJaroslav Kysela snd_iprintf(buffer, " inactive\n"); 1617e74670b6SJaroslav Kysela return; 1618e74670b6SJaroslav Kysela } 1619e74670b6SJaroslav Kysela snd_iprintf(buffer, " buffer_size:\t%u\n", dpcm->pcm_buffer_size); 1620e74670b6SJaroslav Kysela snd_iprintf(buffer, " buffer_pos:\t\t%u\n", dpcm->buf_pos); 1621e74670b6SJaroslav Kysela snd_iprintf(buffer, " silent_size:\t%u\n", dpcm->silent_size); 1622e74670b6SJaroslav Kysela snd_iprintf(buffer, " period_size:\t%u\n", dpcm->pcm_period_size); 1623e74670b6SJaroslav Kysela snd_iprintf(buffer, " bytes_per_sec:\t%u\n", dpcm->pcm_bps); 1624e74670b6SJaroslav Kysela snd_iprintf(buffer, " sample_align:\t%u\n", dpcm->pcm_salign); 1625e74670b6SJaroslav Kysela snd_iprintf(buffer, " rate_shift:\t\t%u\n", dpcm->pcm_rate_shift); 1626133f3759STimo Wischer if (dpcm->cable->ops->dpcm_info) 1627133f3759STimo Wischer dpcm->cable->ops->dpcm_info(dpcm, buffer); 1628e74670b6SJaroslav Kysela } 1629e74670b6SJaroslav Kysela 1630e74670b6SJaroslav Kysela static void print_substream_info(struct snd_info_buffer *buffer, 1631e74670b6SJaroslav Kysela struct loopback *loopback, 1632e74670b6SJaroslav Kysela int sub, 1633e74670b6SJaroslav Kysela int num) 1634e74670b6SJaroslav Kysela { 1635e74670b6SJaroslav Kysela struct loopback_cable *cable = loopback->cables[sub][num]; 1636e74670b6SJaroslav Kysela 1637e74670b6SJaroslav Kysela snd_iprintf(buffer, "Cable %i substream %i:\n", num, sub); 1638e74670b6SJaroslav Kysela if (cable == NULL) { 1639e74670b6SJaroslav Kysela snd_iprintf(buffer, " inactive\n"); 1640e74670b6SJaroslav Kysela return; 1641e74670b6SJaroslav Kysela } 1642e74670b6SJaroslav Kysela snd_iprintf(buffer, " valid: %u\n", cable->valid); 1643e74670b6SJaroslav Kysela snd_iprintf(buffer, " running: %u\n", cable->running); 16445de9e45fSJaroslav Kysela snd_iprintf(buffer, " pause: %u\n", cable->pause); 1645e74670b6SJaroslav Kysela print_dpcm_info(buffer, cable->streams[0], "Playback"); 1646e74670b6SJaroslav Kysela print_dpcm_info(buffer, cable->streams[1], "Capture"); 1647e74670b6SJaroslav Kysela } 1648e74670b6SJaroslav Kysela 1649e74670b6SJaroslav Kysela static void print_cable_info(struct snd_info_entry *entry, 1650e74670b6SJaroslav Kysela struct snd_info_buffer *buffer) 1651e74670b6SJaroslav Kysela { 1652e74670b6SJaroslav Kysela struct loopback *loopback = entry->private_data; 1653e74670b6SJaroslav Kysela int sub, num; 1654e74670b6SJaroslav Kysela 1655e74670b6SJaroslav Kysela mutex_lock(&loopback->cable_lock); 1656e74670b6SJaroslav Kysela num = entry->name[strlen(entry->name)-1]; 1657e74670b6SJaroslav Kysela num = num == '0' ? 0 : 1; 1658e74670b6SJaroslav Kysela for (sub = 0; sub < MAX_PCM_SUBSTREAMS; sub++) 1659e74670b6SJaroslav Kysela print_substream_info(buffer, loopback, sub, num); 1660e74670b6SJaroslav Kysela mutex_unlock(&loopback->cable_lock); 1661e74670b6SJaroslav Kysela } 1662e74670b6SJaroslav Kysela 1663c6ae9960SAndrew Gabbasov static int loopback_cable_proc_new(struct loopback *loopback, int cidx) 1664e74670b6SJaroslav Kysela { 1665e74670b6SJaroslav Kysela char name[32]; 1666e74670b6SJaroslav Kysela 1667e74670b6SJaroslav Kysela snprintf(name, sizeof(name), "cable#%d", cidx); 1668815d808cSTakashi Iwai return snd_card_ro_proc_new(loopback->card, name, loopback, 1669815d808cSTakashi Iwai print_cable_info); 1670e74670b6SJaroslav Kysela } 1671e74670b6SJaroslav Kysela 167226c53379STimo Wischer static void loopback_set_timer_source(struct loopback *loopback, 167326c53379STimo Wischer const char *value) 167426c53379STimo Wischer { 167526c53379STimo Wischer if (loopback->timer_source) { 167626c53379STimo Wischer devm_kfree(loopback->card->dev, loopback->timer_source); 167726c53379STimo Wischer loopback->timer_source = NULL; 167826c53379STimo Wischer } 167926c53379STimo Wischer if (value && *value) 168026c53379STimo Wischer loopback->timer_source = devm_kstrdup(loopback->card->dev, 168126c53379STimo Wischer value, GFP_KERNEL); 168226c53379STimo Wischer } 168326c53379STimo Wischer 1684c6ae9960SAndrew Gabbasov static void print_timer_source_info(struct snd_info_entry *entry, 1685c6ae9960SAndrew Gabbasov struct snd_info_buffer *buffer) 1686c6ae9960SAndrew Gabbasov { 1687c6ae9960SAndrew Gabbasov struct loopback *loopback = entry->private_data; 1688c6ae9960SAndrew Gabbasov 1689c6ae9960SAndrew Gabbasov mutex_lock(&loopback->cable_lock); 1690c6ae9960SAndrew Gabbasov snd_iprintf(buffer, "%s\n", 1691c6ae9960SAndrew Gabbasov loopback->timer_source ? loopback->timer_source : ""); 1692c6ae9960SAndrew Gabbasov mutex_unlock(&loopback->cable_lock); 1693c6ae9960SAndrew Gabbasov } 1694c6ae9960SAndrew Gabbasov 1695c6ae9960SAndrew Gabbasov static void change_timer_source_info(struct snd_info_entry *entry, 1696c6ae9960SAndrew Gabbasov struct snd_info_buffer *buffer) 1697c6ae9960SAndrew Gabbasov { 1698c6ae9960SAndrew Gabbasov struct loopback *loopback = entry->private_data; 1699c6ae9960SAndrew Gabbasov char line[64]; 1700c6ae9960SAndrew Gabbasov 1701c6ae9960SAndrew Gabbasov mutex_lock(&loopback->cable_lock); 1702c6ae9960SAndrew Gabbasov if (!snd_info_get_line(buffer, line, sizeof(line))) 1703c6ae9960SAndrew Gabbasov loopback_set_timer_source(loopback, strim(line)); 1704c6ae9960SAndrew Gabbasov mutex_unlock(&loopback->cable_lock); 1705c6ae9960SAndrew Gabbasov } 1706c6ae9960SAndrew Gabbasov 1707c6ae9960SAndrew Gabbasov static int loopback_timer_source_proc_new(struct loopback *loopback) 1708c6ae9960SAndrew Gabbasov { 1709c6ae9960SAndrew Gabbasov return snd_card_rw_proc_new(loopback->card, "timer_source", loopback, 1710c6ae9960SAndrew Gabbasov print_timer_source_info, 1711c6ae9960SAndrew Gabbasov change_timer_source_info); 1712c6ae9960SAndrew Gabbasov } 1713c6ae9960SAndrew Gabbasov 1714fbbb01a1SBill Pemberton static int loopback_probe(struct platform_device *devptr) 1715597603d6SJaroslav Kysela { 1716597603d6SJaroslav Kysela struct snd_card *card; 1717597603d6SJaroslav Kysela struct loopback *loopback; 1718597603d6SJaroslav Kysela int dev = devptr->id; 1719597603d6SJaroslav Kysela int err; 1720597603d6SJaroslav Kysela 17215872f3f6STakashi Iwai err = snd_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE, 1722597603d6SJaroslav Kysela sizeof(struct loopback), &card); 1723597603d6SJaroslav Kysela if (err < 0) 1724597603d6SJaroslav Kysela return err; 1725597603d6SJaroslav Kysela loopback = card->private_data; 1726597603d6SJaroslav Kysela 1727597603d6SJaroslav Kysela if (pcm_substreams[dev] < 1) 1728597603d6SJaroslav Kysela pcm_substreams[dev] = 1; 1729597603d6SJaroslav Kysela if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS) 1730597603d6SJaroslav Kysela pcm_substreams[dev] = MAX_PCM_SUBSTREAMS; 1731597603d6SJaroslav Kysela 1732597603d6SJaroslav Kysela loopback->card = card; 173326c53379STimo Wischer loopback_set_timer_source(loopback, timer_source[dev]); 173426c53379STimo Wischer 1735597603d6SJaroslav Kysela mutex_init(&loopback->cable_lock); 1736597603d6SJaroslav Kysela 1737597603d6SJaroslav Kysela err = loopback_pcm_new(loopback, 0, pcm_substreams[dev]); 1738597603d6SJaroslav Kysela if (err < 0) 1739597603d6SJaroslav Kysela goto __nodev; 1740597603d6SJaroslav Kysela err = loopback_pcm_new(loopback, 1, pcm_substreams[dev]); 1741597603d6SJaroslav Kysela if (err < 0) 1742597603d6SJaroslav Kysela goto __nodev; 1743597603d6SJaroslav Kysela err = loopback_mixer_new(loopback, pcm_notify[dev] ? 1 : 0); 1744597603d6SJaroslav Kysela if (err < 0) 1745597603d6SJaroslav Kysela goto __nodev; 1746c6ae9960SAndrew Gabbasov loopback_cable_proc_new(loopback, 0); 1747c6ae9960SAndrew Gabbasov loopback_cable_proc_new(loopback, 1); 1748c6ae9960SAndrew Gabbasov loopback_timer_source_proc_new(loopback); 1749597603d6SJaroslav Kysela strcpy(card->driver, "Loopback"); 1750597603d6SJaroslav Kysela strcpy(card->shortname, "Loopback"); 1751597603d6SJaroslav Kysela sprintf(card->longname, "Loopback %i", dev + 1); 1752597603d6SJaroslav Kysela err = snd_card_register(card); 1753597603d6SJaroslav Kysela if (!err) { 1754597603d6SJaroslav Kysela platform_set_drvdata(devptr, card); 1755597603d6SJaroslav Kysela return 0; 1756597603d6SJaroslav Kysela } 1757597603d6SJaroslav Kysela __nodev: 1758597603d6SJaroslav Kysela snd_card_free(card); 1759597603d6SJaroslav Kysela return err; 1760597603d6SJaroslav Kysela } 1761597603d6SJaroslav Kysela 1762fbbb01a1SBill Pemberton static int loopback_remove(struct platform_device *devptr) 1763597603d6SJaroslav Kysela { 1764597603d6SJaroslav Kysela snd_card_free(platform_get_drvdata(devptr)); 1765597603d6SJaroslav Kysela return 0; 1766597603d6SJaroslav Kysela } 1767597603d6SJaroslav Kysela 1768d34e4e00STakashi Iwai #ifdef CONFIG_PM_SLEEP 1769284e7ca7STakashi Iwai static int loopback_suspend(struct device *pdev) 1770597603d6SJaroslav Kysela { 1771284e7ca7STakashi Iwai struct snd_card *card = dev_get_drvdata(pdev); 1772597603d6SJaroslav Kysela 1773597603d6SJaroslav Kysela snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 1774597603d6SJaroslav Kysela return 0; 1775597603d6SJaroslav Kysela } 1776597603d6SJaroslav Kysela 1777284e7ca7STakashi Iwai static int loopback_resume(struct device *pdev) 1778597603d6SJaroslav Kysela { 1779284e7ca7STakashi Iwai struct snd_card *card = dev_get_drvdata(pdev); 1780597603d6SJaroslav Kysela 1781597603d6SJaroslav Kysela snd_power_change_state(card, SNDRV_CTL_POWER_D0); 1782597603d6SJaroslav Kysela return 0; 1783597603d6SJaroslav Kysela } 1784284e7ca7STakashi Iwai 1785284e7ca7STakashi Iwai static SIMPLE_DEV_PM_OPS(loopback_pm, loopback_suspend, loopback_resume); 1786284e7ca7STakashi Iwai #define LOOPBACK_PM_OPS &loopback_pm 1787284e7ca7STakashi Iwai #else 1788284e7ca7STakashi Iwai #define LOOPBACK_PM_OPS NULL 1789597603d6SJaroslav Kysela #endif 1790597603d6SJaroslav Kysela 1791597603d6SJaroslav Kysela #define SND_LOOPBACK_DRIVER "snd_aloop" 1792597603d6SJaroslav Kysela 1793597603d6SJaroslav Kysela static struct platform_driver loopback_driver = { 1794597603d6SJaroslav Kysela .probe = loopback_probe, 1795fbbb01a1SBill Pemberton .remove = loopback_remove, 1796597603d6SJaroslav Kysela .driver = { 17978bf01d8aSTakashi Iwai .name = SND_LOOPBACK_DRIVER, 1798284e7ca7STakashi Iwai .pm = LOOPBACK_PM_OPS, 1799597603d6SJaroslav Kysela }, 1800597603d6SJaroslav Kysela }; 1801597603d6SJaroslav Kysela 1802597603d6SJaroslav Kysela static void loopback_unregister_all(void) 1803597603d6SJaroslav Kysela { 1804597603d6SJaroslav Kysela int i; 1805597603d6SJaroslav Kysela 1806597603d6SJaroslav Kysela for (i = 0; i < ARRAY_SIZE(devices); ++i) 1807597603d6SJaroslav Kysela platform_device_unregister(devices[i]); 1808597603d6SJaroslav Kysela platform_driver_unregister(&loopback_driver); 1809597603d6SJaroslav Kysela } 1810597603d6SJaroslav Kysela 1811597603d6SJaroslav Kysela static int __init alsa_card_loopback_init(void) 1812597603d6SJaroslav Kysela { 1813597603d6SJaroslav Kysela int i, err, cards; 1814597603d6SJaroslav Kysela 1815597603d6SJaroslav Kysela err = platform_driver_register(&loopback_driver); 1816597603d6SJaroslav Kysela if (err < 0) 1817597603d6SJaroslav Kysela return err; 1818597603d6SJaroslav Kysela 1819597603d6SJaroslav Kysela 1820597603d6SJaroslav Kysela cards = 0; 1821597603d6SJaroslav Kysela for (i = 0; i < SNDRV_CARDS; i++) { 1822597603d6SJaroslav Kysela struct platform_device *device; 1823597603d6SJaroslav Kysela if (!enable[i]) 1824597603d6SJaroslav Kysela continue; 1825597603d6SJaroslav Kysela device = platform_device_register_simple(SND_LOOPBACK_DRIVER, 1826597603d6SJaroslav Kysela i, NULL, 0); 1827597603d6SJaroslav Kysela if (IS_ERR(device)) 1828597603d6SJaroslav Kysela continue; 1829597603d6SJaroslav Kysela if (!platform_get_drvdata(device)) { 1830597603d6SJaroslav Kysela platform_device_unregister(device); 1831597603d6SJaroslav Kysela continue; 1832597603d6SJaroslav Kysela } 1833597603d6SJaroslav Kysela devices[i] = device; 1834597603d6SJaroslav Kysela cards++; 1835597603d6SJaroslav Kysela } 1836597603d6SJaroslav Kysela if (!cards) { 1837597603d6SJaroslav Kysela #ifdef MODULE 1838597603d6SJaroslav Kysela printk(KERN_ERR "aloop: No loopback enabled\n"); 1839597603d6SJaroslav Kysela #endif 1840597603d6SJaroslav Kysela loopback_unregister_all(); 1841597603d6SJaroslav Kysela return -ENODEV; 1842597603d6SJaroslav Kysela } 1843597603d6SJaroslav Kysela return 0; 1844597603d6SJaroslav Kysela } 1845597603d6SJaroslav Kysela 1846597603d6SJaroslav Kysela static void __exit alsa_card_loopback_exit(void) 1847597603d6SJaroslav Kysela { 1848597603d6SJaroslav Kysela loopback_unregister_all(); 1849597603d6SJaroslav Kysela } 1850597603d6SJaroslav Kysela 1851597603d6SJaroslav Kysela module_init(alsa_card_loopback_init) 1852597603d6SJaroslav Kysela module_exit(alsa_card_loopback_exit) 1853