Commit 29bb274e authored by Takashi Iwai's avatar Takashi Iwai

ALSA: pcm: Call sync_stop at disconnection

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: 1e850bee ("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.deSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 257d2d7e
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/interrupt.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/control.h> #include <sound/control.h>
...@@ -426,6 +427,9 @@ int snd_card_disconnect(struct snd_card *card) ...@@ -426,6 +427,9 @@ int snd_card_disconnect(struct snd_card *card)
/* notify all devices that we are disconnected */ /* notify all devices that we are disconnected */
snd_device_disconnect_all(card); snd_device_disconnect_all(card);
if (card->sync_irq > 0)
synchronize_irq(card->sync_irq);
snd_info_card_disconnect(card); snd_info_card_disconnect(card);
if (card->registered) { if (card->registered) {
device_del(&card->card_dev); device_del(&card->card_dev);
......
...@@ -1111,6 +1111,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) ...@@ -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); pcm_call_notify(pcm, n_disconnect);
for (cidx = 0; cidx < 2; cidx++) { for (cidx = 0; cidx < 2; cidx++) {
snd_unregister_device(&pcm->streams[cidx].dev); snd_unregister_device(&pcm->streams[cidx].dev);
......
...@@ -63,6 +63,7 @@ static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {} ...@@ -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_xrun(struct snd_pcm_substream *substream);
void snd_pcm_group_init(struct snd_pcm_group *group); 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 #ifdef CONFIG_SND_DMA_SGBUF
struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,
......
...@@ -583,13 +583,13 @@ static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream, ...@@ -583,13 +583,13 @@ static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
#endif #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; substream->runtime->stop_operating = false;
if (substream->ops->sync_stop) if (substream->ops && substream->ops->sync_stop)
substream->ops->sync_stop(substream); 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); synchronize_irq(substream->pcm->card->sync_irq);
} }
} }
...@@ -686,7 +686,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -686,7 +686,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
if (atomic_read(&substream->mmap_count)) if (atomic_read(&substream->mmap_count))
return -EBADFD; return -EBADFD;
snd_pcm_sync_stop(substream); snd_pcm_sync_stop(substream, true);
params->rmask = ~0U; params->rmask = ~0U;
err = snd_pcm_hw_refine(substream, params); err = snd_pcm_hw_refine(substream, params);
...@@ -809,7 +809,7 @@ static int do_hw_free(struct snd_pcm_substream *substream) ...@@ -809,7 +809,7 @@ static int do_hw_free(struct snd_pcm_substream *substream)
{ {
int result = 0; int result = 0;
snd_pcm_sync_stop(substream); snd_pcm_sync_stop(substream, true);
if (substream->ops->hw_free) if (substream->ops->hw_free)
result = substream->ops->hw_free(substream); result = substream->ops->hw_free(substream);
if (substream->managed_buffer_alloc) if (substream->managed_buffer_alloc)
...@@ -1736,7 +1736,7 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream, ...@@ -1736,7 +1736,7 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream,
snd_pcm_trigger_tstamp(substream); snd_pcm_trigger_tstamp(substream);
runtime->status->state = runtime->status->suspended_state; runtime->status->state = runtime->status->suspended_state;
snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MRESUME); 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 = { static const struct action_ops snd_pcm_action_resume = {
...@@ -1866,7 +1866,7 @@ static int snd_pcm_do_prepare(struct snd_pcm_substream *substream, ...@@ -1866,7 +1866,7 @@ static int snd_pcm_do_prepare(struct snd_pcm_substream *substream,
snd_pcm_state_t state) snd_pcm_state_t state)
{ {
int err; int err;
snd_pcm_sync_stop(substream); snd_pcm_sync_stop(substream, true);
err = substream->ops->prepare(substream); err = substream->ops->prepare(substream);
if (err < 0) if (err < 0)
return err; return err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment