summaryrefslogtreecommitdiff
path: root/sound/core/init.c
diff options
context:
space:
mode:
authorJames Morris <james.l.morris@oracle.com>2017-11-29 12:47:41 +1100
committerJames Morris <james.l.morris@oracle.com>2017-11-29 12:47:41 +1100
commitcf40a76e7d5874bb25f4404eecc58a2e033af885 (patch)
tree8fd81cbea03c87b3d41d7ae5b1d11eadd35d6ef5 /sound/core/init.c
parentab5348c9c23cd253f5902980d2d8fe067dc24c82 (diff)
parent4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323 (diff)
Merge tag 'v4.15-rc1' into next-seccomp
Linux 4.15-rc1
Diffstat (limited to 'sound/core/init.c')
-rw-r--r--sound/core/init.c38
1 files changed, 32 insertions, 6 deletions
diff --git a/sound/core/init.c b/sound/core/init.c
index b4365bcf28a7..168ae03d3a1c 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -248,15 +248,14 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
INIT_LIST_HEAD(&card->devices);
init_rwsem(&card->controls_rwsem);
rwlock_init(&card->ctl_files_rwlock);
- mutex_init(&card->user_ctl_lock);
INIT_LIST_HEAD(&card->controls);
INIT_LIST_HEAD(&card->ctl_files);
spin_lock_init(&card->files_lock);
INIT_LIST_HEAD(&card->files_list);
#ifdef CONFIG_PM
- mutex_init(&card->power_lock);
init_waitqueue_head(&card->power_sleep);
#endif
+ init_waitqueue_head(&card->remove_sleep);
device_initialize(&card->card_dev);
card->card_dev.parent = parent;
@@ -454,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)
@@ -959,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);
@@ -979,8 +1009,6 @@ EXPORT_SYMBOL(snd_card_file_remove);
* Waits until the power-state is changed.
*
* Return: Zero if successful, or a negative error code.
- *
- * Note: the power lock must be active before call.
*/
int snd_power_wait(struct snd_card *card, unsigned int power_state)
{
@@ -1000,9 +1028,7 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state)
if (snd_power_get_state(card) == power_state)
break;
set_current_state(TASK_UNINTERRUPTIBLE);
- snd_power_unlock(card);
schedule_timeout(30 * HZ);
- snd_power_lock(card);
}
remove_wait_queue(&card->power_sleep, &wait);
return result;