diff options
author | Takashi Iwai <tiwai@suse.de> | 2017-10-24 08:15:10 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2017-10-24 08:15:49 +0200 |
commit | 1a0190157521704c11f8650756388b62f3887eb3 (patch) | |
tree | 25bb473c628872f05a1a1a97161d2dae9ce1c1d4 /sound/core/init.c | |
parent | b676da70c495acb2515de76300596e9147806ead (diff) | |
parent | 6ca73de7ebc5dac358551633e0c69ab6b5007baa (diff) | |
download | linux-1a0190157521704c11f8650756388b62f3887eb3.tar.bz2 |
Merge branch 'topic/card-disconnect' into for-next
Pull snd_card_disconnect_sync() extension for ASoC hot-unplug support.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core/init.c')
-rw-r--r-- | sound/core/init.c | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/sound/core/init.c b/sound/core/init.c index 32ebe2f6bc59..168ae03d3a1c 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -255,6 +255,7 @@ int snd_card_new(struct device *parent, int idx, const char *xid, #ifdef CONFIG_PM init_waitqueue_head(&card->power_sleep); #endif + init_waitqueue_head(&card->remove_sleep); device_initialize(&card->card_dev); card->card_dev.parent = parent; @@ -452,6 +453,35 @@ int snd_card_disconnect(struct snd_card *card) } EXPORT_SYMBOL(snd_card_disconnect); +/** + * snd_card_disconnect_sync - disconnect card and wait until files get closed + * @card: card object to disconnect + * + * This calls snd_card_disconnect() for disconnecting all belonging components + * and waits until all pending files get closed. + * It assures that all accesses from user-space finished so that the driver + * can release its resources gracefully. + */ +void snd_card_disconnect_sync(struct snd_card *card) +{ + int err; + + err = snd_card_disconnect(card); + if (err < 0) { + dev_err(card->dev, + "snd_card_disconnect error (%d), skipping sync\n", + err); + return; + } + + spin_lock_irq(&card->files_lock); + wait_event_lock_irq(card->remove_sleep, + list_empty(&card->files_list), + card->files_lock); + spin_unlock_irq(&card->files_lock); +} +EXPORT_SYMBOL_GPL(snd_card_disconnect_sync); + static int snd_card_do_free(struct snd_card *card) { #if IS_ENABLED(CONFIG_SND_MIXER_OSS) @@ -957,6 +987,8 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) break; } } + if (list_empty(&card->files_list)) + wake_up_all(&card->remove_sleep); spin_unlock(&card->files_lock); if (!found) { dev_err(card->dev, "card file remove problem (%p)\n", file); |