mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-02-05 09:05:24 +07:00
ALSA: pcm: Call sync_stop at disconnection
commit 29bb274e94974669acb5186a75538f20df1508b6 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: 1e850beea2
("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>
This commit is contained in:
parent
85c1062920
commit
6bcf443bce
@ -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>
|
||||
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
@ -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)
|
||||
@ -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 = {
|
||||
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user