From e74670b6fdc37b15ebee11825849d8983e52a74a Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 18 Oct 2010 09:43:10 +0200 Subject: ALSA: snd-aloop: add cable#0 and cable#1 files to proc card tree Show some useful runtime information using procfs. Signed-off-by: Jaroslav Kysela --- sound/drivers/aloop.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 838ad86311b8..66786ea6f480 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -39,6 +39,7 @@ #include #include #include +#include #include MODULE_AUTHOR("Jaroslav Kysela "); @@ -184,6 +185,7 @@ static void loopback_timer_start(struct loopback_pcm *dpcm) static inline void loopback_timer_stop(struct loopback_pcm *dpcm) { del_timer(&dpcm->timer); + dpcm->timer.expires = 0; } #define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK) @@ -1011,6 +1013,86 @@ static int __devinit loopback_mixer_new(struct loopback *loopback, int notify) return 0; } +#ifdef CONFIG_PROC_FS + +static void print_dpcm_info(struct snd_info_buffer *buffer, + struct loopback_pcm *dpcm, + const char *id) +{ + snd_iprintf(buffer, " %s\n", id); + if (dpcm == NULL) { + snd_iprintf(buffer, " inactive\n"); + return; + } + snd_iprintf(buffer, " buffer_size:\t%u\n", dpcm->pcm_buffer_size); + snd_iprintf(buffer, " buffer_pos:\t\t%u\n", dpcm->buf_pos); + snd_iprintf(buffer, " silent_size:\t%u\n", dpcm->silent_size); + snd_iprintf(buffer, " period_size:\t%u\n", dpcm->pcm_period_size); + snd_iprintf(buffer, " bytes_per_sec:\t%u\n", dpcm->pcm_bps); + snd_iprintf(buffer, " sample_align:\t%u\n", dpcm->pcm_salign); + snd_iprintf(buffer, " rate_shift:\t\t%u\n", dpcm->pcm_rate_shift); + snd_iprintf(buffer, " update_pending:\t%u\n", + dpcm->period_update_pending); + snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos); + snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac); + snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n", + dpcm->last_jiffies, jiffies); + snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires); +} + +static void print_substream_info(struct snd_info_buffer *buffer, + struct loopback *loopback, + int sub, + int num) +{ + struct loopback_cable *cable = loopback->cables[sub][num]; + + snd_iprintf(buffer, "Cable %i substream %i:\n", num, sub); + if (cable == NULL) { + snd_iprintf(buffer, " inactive\n"); + return; + } + snd_iprintf(buffer, " valid: %u\n", cable->valid); + snd_iprintf(buffer, " running: %u\n", cable->running); + print_dpcm_info(buffer, cable->streams[0], "Playback"); + print_dpcm_info(buffer, cable->streams[1], "Capture"); +} + +static void print_cable_info(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct loopback *loopback = entry->private_data; + int sub, num; + + mutex_lock(&loopback->cable_lock); + num = entry->name[strlen(entry->name)-1]; + num = num == '0' ? 0 : 1; + for (sub = 0; sub < MAX_PCM_SUBSTREAMS; sub++) + print_substream_info(buffer, loopback, sub, num); + mutex_unlock(&loopback->cable_lock); +} + +static int __devinit loopback_proc_new(struct loopback *loopback, int cidx) +{ + char name[32]; + struct snd_info_entry *entry; + int err; + + snprintf(name, sizeof(name), "cable#%d", cidx); + err = snd_card_proc_new(loopback->card, name, &entry); + if (err < 0) + return err; + + snd_info_set_text_ops(entry, loopback, print_cable_info); + return 0; +} + +#else /* !CONFIG_PROC_FS */ + +#define loopback_proc_new(loopback, cidx) do { } while (0) + +#endif + static int __devinit loopback_probe(struct platform_device *devptr) { struct snd_card *card; @@ -1041,6 +1123,8 @@ static int __devinit loopback_probe(struct platform_device *devptr) err = loopback_mixer_new(loopback, pcm_notify[dev] ? 1 : 0); if (err < 0) goto __nodev; + loopback_proc_new(loopback, 0); + loopback_proc_new(loopback, 1); strcpy(card->driver, "Loopback"); strcpy(card->shortname, "Loopback"); sprintf(card->longname, "Loopback %i", dev + 1); -- cgit v1.2.3 From dd04bb12d047a4d4461772093472a40dbe171e5f Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 20 Oct 2010 08:27:02 +0200 Subject: ALSA: snd-aloop - fix locking issues (running flag updates) On SMP machines, the cable->running update must be atomic, otherwise stream is not started correctly sometimes. Signed-off-by: Jaroslav Kysela --- sound/drivers/aloop.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 66786ea6f480..38e8351e935d 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -263,13 +263,17 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) return err; dpcm->last_jiffies = jiffies; dpcm->pcm_rate_shift = 0; - loopback_timer_start(dpcm); + spin_lock(&cable->lock); cable->running |= (1 << substream->stream); + spin_unlock(&cable->lock); + loopback_timer_start(dpcm); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); break; case SNDRV_PCM_TRIGGER_STOP: + spin_lock(&cable->lock); cable->running &= ~(1 << substream->stream); + spin_unlock(&cable->lock); loopback_timer_stop(dpcm); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); @@ -454,28 +458,30 @@ static void loopback_bytepos_update(struct loopback_pcm *dpcm, } } -static void loopback_pos_update(struct loopback_cable *cable) +static unsigned int loopback_pos_update(struct loopback_cable *cable) { struct loopback_pcm *dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; struct loopback_pcm *dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE]; unsigned long delta_play = 0, delta_capt = 0; + unsigned int running; spin_lock(&cable->lock); - if (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { + running = cable->running; + if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { delta_play = jiffies - dpcm_play->last_jiffies; dpcm_play->last_jiffies += delta_play; } - if (cable->running & (1 << SNDRV_PCM_STREAM_CAPTURE)) { + if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) { delta_capt = jiffies - dpcm_capt->last_jiffies; dpcm_capt->last_jiffies += delta_capt; } if (delta_play == 0 && delta_capt == 0) { spin_unlock(&cable->lock); - return; + return running; } if (delta_play > delta_capt) { @@ -490,27 +496,27 @@ static void loopback_pos_update(struct loopback_cable *cable) if (delta_play == 0 && delta_capt == 0) { spin_unlock(&cable->lock); - return; + return running; } /* note delta_capt == delta_play at this moment */ loopback_bytepos_update(dpcm_capt, delta_capt, BYTEPOS_UPDATE_COPY); loopback_bytepos_update(dpcm_play, delta_play, BYTEPOS_UPDATE_POSONLY); spin_unlock(&cable->lock); + return running; } static void loopback_timer_function(unsigned long data) { struct loopback_pcm *dpcm = (struct loopback_pcm *)data; - int stream; + unsigned int running; - loopback_pos_update(dpcm->cable); - stream = dpcm->substream->stream; - if (dpcm->cable->running & (1 << stream)) + running = loopback_pos_update(dpcm->cable); + if (running & (1 << dpcm->substream->stream)) { loopback_timer_start(dpcm); - if (dpcm->period_update_pending) { - dpcm->period_update_pending = 0; - if (dpcm->cable->running & (1 << stream)) + if (dpcm->period_update_pending) { + dpcm->period_update_pending = 0; snd_pcm_period_elapsed(dpcm->substream); + } } } -- cgit v1.2.3 From 5de9e45fcfccdf8151a82fc1a521e7042cbe482a Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 20 Oct 2010 09:33:03 +0200 Subject: ALSA: snd-aloop - add pause support Signed-off-by: Jaroslav Kysela --- sound/drivers/aloop.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 38e8351e935d..12b44b0b6777 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -77,6 +77,7 @@ struct loopback_cable { /* flags */ unsigned int valid; unsigned int running; + unsigned int pause; }; struct loopback_setup { @@ -254,7 +255,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_pcm_runtime *runtime = substream->runtime; struct loopback_pcm *dpcm = runtime->private_data; struct loopback_cable *cable = dpcm->cable; - int err; + int err, stream = 1 << substream->stream; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -264,7 +265,8 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) dpcm->last_jiffies = jiffies; dpcm->pcm_rate_shift = 0; spin_lock(&cable->lock); - cable->running |= (1 << substream->stream); + cable->running |= stream; + cable->pause &= ~stream; spin_unlock(&cable->lock); loopback_timer_start(dpcm); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -272,12 +274,26 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) break; case SNDRV_PCM_TRIGGER_STOP: spin_lock(&cable->lock); - cable->running &= ~(1 << substream->stream); + cable->running &= ~stream; + cable->pause &= ~stream; spin_unlock(&cable->lock); loopback_timer_stop(dpcm); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) loopback_active_notify(dpcm); break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + spin_lock(&cable->lock); + cable->pause |= stream; + spin_unlock(&cable->lock); + loopback_timer_stop(dpcm); + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + spin_lock(&cable->lock); + dpcm->last_jiffies = jiffies; + cable->pause &= ~stream; + spin_unlock(&cable->lock); + loopback_timer_start(dpcm); + break; default: return -EINVAL; } @@ -468,7 +484,7 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable) unsigned int running; spin_lock(&cable->lock); - running = cable->running; + running = cable->running ^ cable->pause; if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { delta_play = jiffies - dpcm_play->last_jiffies; dpcm_play->last_jiffies += delta_play; @@ -532,7 +548,7 @@ static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) static struct snd_pcm_hardware loopback_pcm_hardware = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID), + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE), @@ -1060,6 +1076,7 @@ static void print_substream_info(struct snd_info_buffer *buffer, } snd_iprintf(buffer, " valid: %u\n", cable->valid); snd_iprintf(buffer, " running: %u\n", cable->running); + snd_iprintf(buffer, " pause: %u\n", cable->pause); print_dpcm_info(buffer, cable->streams[0], "Playback"); print_dpcm_info(buffer, cable->streams[1], "Capture"); } -- cgit v1.2.3