Skip to content

Commit

Permalink
ALSA: pcm: Call sync_stop at disconnection
Browse files Browse the repository at this point in the history
commit 29bb274 upstream.

The PCM core should perform the sync for the pending stop operations
at disconnection.  Otherwise it may lead to unexpected access.

Currently the old user of sync_stop, USB-audio driver, has its own
sync, so this isn't needed, but it's better to guarantee the sync in
the PCM core level.

This patch adds the missing sync_stop call at PCM disconnection
callback.  It also assures the IRQ sync if it's specified in the
card.  snd_pcm_sync_stop() is slightly modified to be called also for
any PCM substream object now.

Fixes: 1e850be ("ALSA: pcm: Add the support for sync-stop operation")
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20210206203656.15959-2-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
tiwai authored and gregkh committed Mar 4, 2021
1 parent 85c1062 commit 6bcf443
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 8 deletions.
4 changes: 4 additions & 0 deletions sound/core/init.c
Expand Up @@ -14,6 +14,7 @@
#include <linux/ctype.h>
#include <linux/pm.h>
#include <linux/completion.h>
#include <linux/interrupt.h>

#include <sound/core.h>
#include <sound/control.h>
Expand Down Expand Up @@ -418,6 +419,9 @@ int snd_card_disconnect(struct snd_card *card)
/* notify all devices that we are disconnected */
snd_device_disconnect_all(card);

if (card->sync_irq > 0)
synchronize_irq(card->sync_irq);

snd_info_card_disconnect(card);
if (card->registered) {
device_del(&card->card_dev);
Expand Down
4 changes: 4 additions & 0 deletions sound/core/pcm.c
Expand Up @@ -1111,6 +1111,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
}
}

for (cidx = 0; cidx < 2; cidx++)
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
snd_pcm_sync_stop(substream, false);

pcm_call_notify(pcm, n_disconnect);
for (cidx = 0; cidx < 2; cidx++) {
snd_unregister_device(&pcm->streams[cidx].dev);
Expand Down
1 change: 1 addition & 0 deletions sound/core/pcm_local.h
Expand Up @@ -63,6 +63,7 @@ static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {}

void __snd_pcm_xrun(struct snd_pcm_substream *substream);
void snd_pcm_group_init(struct snd_pcm_group *group);
void snd_pcm_sync_stop(struct snd_pcm_substream *substream, bool sync_irq);

#ifdef CONFIG_SND_DMA_SGBUF
struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,
Expand Down
16 changes: 8 additions & 8 deletions sound/core/pcm_native.c
Expand Up @@ -583,13 +583,13 @@ static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
#endif
}

static void snd_pcm_sync_stop(struct snd_pcm_substream *substream)
void snd_pcm_sync_stop(struct snd_pcm_substream *substream, bool sync_irq)
{
if (substream->runtime->stop_operating) {
if (substream->runtime && substream->runtime->stop_operating) {
substream->runtime->stop_operating = false;
if (substream->ops->sync_stop)
if (substream->ops && substream->ops->sync_stop)
substream->ops->sync_stop(substream);
else if (substream->pcm->card->sync_irq > 0)
else if (sync_irq && substream->pcm->card->sync_irq > 0)
synchronize_irq(substream->pcm->card->sync_irq);
}
}
Expand Down Expand Up @@ -686,7 +686,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
if (atomic_read(&substream->mmap_count))
return -EBADFD;

snd_pcm_sync_stop(substream);
snd_pcm_sync_stop(substream, true);

params->rmask = ~0U;
err = snd_pcm_hw_refine(substream, params);
Expand Down Expand Up @@ -809,7 +809,7 @@ static int do_hw_free(struct snd_pcm_substream *substream)
{
int result = 0;

snd_pcm_sync_stop(substream);
snd_pcm_sync_stop(substream, true);
if (substream->ops->hw_free)
result = substream->ops->hw_free(substream);
if (substream->managed_buffer_alloc)
Expand Down Expand Up @@ -1736,7 +1736,7 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream,
snd_pcm_trigger_tstamp(substream);
runtime->status->state = runtime->status->suspended_state;
snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MRESUME);
snd_pcm_sync_stop(substream);
snd_pcm_sync_stop(substream, true);
}

static const struct action_ops snd_pcm_action_resume = {
Expand Down Expand Up @@ -1866,7 +1866,7 @@ static int snd_pcm_do_prepare(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
int err;
snd_pcm_sync_stop(substream);
snd_pcm_sync_stop(substream, true);
err = substream->ops->prepare(substream);
if (err < 0)
return err;
Expand Down

0 comments on commit 6bcf443

Please sign in to comment.