mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02:00
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: 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>
This commit is contained in:
@@ -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)
|
|||||||
/* 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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {}
|
|||||||
|
|
||||||
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,
|
|||||||
#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,
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
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,
|
|||||||
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;
|
||||||
|
Reference in New Issue
Block a user