mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
ALSA: compress: stop active streams on disconnect
Track open compressed streams per device so disconnect can stop active streams and wake waiters before snd_unregister_device(). This aligns compressed stream teardown with PCM disconnect behavior and prevents active userspace streams from running into unregister races. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Reviewed-by: Liam Girdwood <liam.r.girdwood@intel.com> Reviewed-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20261007084955.1256-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
fd7f98db9c
commit
b04c9229ee
|
|
@ -188,6 +188,7 @@ struct snd_compr_ops {
|
|||
* @card: sound card pointer
|
||||
* @direction: Playback or capture direction
|
||||
* @lock: device lock
|
||||
* @open_list: list of open compress files
|
||||
* @device: device id
|
||||
* @use_pause_in_draining: allow pause in draining, true when set
|
||||
*/
|
||||
|
|
@ -199,6 +200,7 @@ struct snd_compr {
|
|||
struct snd_card *card;
|
||||
unsigned int direction;
|
||||
struct mutex lock;
|
||||
struct list_head open_list;
|
||||
int device;
|
||||
bool use_pause_in_draining;
|
||||
#ifdef CONFIG_SND_VERBOSE_PROCFS
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#endif
|
||||
|
||||
struct snd_compr_file {
|
||||
struct list_head list;
|
||||
unsigned long caps;
|
||||
struct snd_compr_stream stream;
|
||||
};
|
||||
|
|
@ -124,6 +125,7 @@ static int snd_compr_open(struct inode *inode, struct file *f)
|
|||
ret = -ENOMEM;
|
||||
goto __error;
|
||||
}
|
||||
INIT_LIST_HEAD(&data->list);
|
||||
|
||||
INIT_DELAYED_WORK(&data->stream.error_work, error_delayed_work);
|
||||
|
||||
|
|
@ -143,8 +145,11 @@ static int snd_compr_open(struct inode *inode, struct file *f)
|
|||
#endif
|
||||
data->stream.runtime = runtime;
|
||||
f->private_data = (void *)data;
|
||||
scoped_guard(mutex, &compr->lock)
|
||||
scoped_guard(mutex, &compr->lock) {
|
||||
ret = compr->ops->open(&data->stream);
|
||||
if (!ret)
|
||||
list_add_tail(&data->list, &compr->open_list);
|
||||
}
|
||||
|
||||
__error:
|
||||
if (ret) {
|
||||
|
|
@ -165,14 +170,19 @@ static int snd_compr_free(struct inode *inode, struct file *f)
|
|||
|
||||
cancel_delayed_work_sync(&data->stream.error_work);
|
||||
|
||||
switch (runtime->state) {
|
||||
case SNDRV_PCM_STATE_RUNNING:
|
||||
case SNDRV_PCM_STATE_DRAINING:
|
||||
case SNDRV_PCM_STATE_PAUSED:
|
||||
data->stream.ops->trigger(&data->stream, SNDRV_PCM_TRIGGER_STOP);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
scoped_guard(mutex, &compr->lock) {
|
||||
if (!list_empty(&data->list))
|
||||
list_del_init(&data->list);
|
||||
|
||||
switch (runtime->state) {
|
||||
case SNDRV_PCM_STATE_RUNNING:
|
||||
case SNDRV_PCM_STATE_DRAINING:
|
||||
case SNDRV_PCM_STATE_PAUSED:
|
||||
data->stream.ops->trigger(&data->stream, SNDRV_PCM_TRIGGER_STOP);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
snd_compr_task_free_all(&data->stream);
|
||||
|
|
@ -1450,8 +1460,27 @@ static int snd_compress_dev_register(struct snd_device *device)
|
|||
static int snd_compress_dev_disconnect(struct snd_device *device)
|
||||
{
|
||||
struct snd_compr *compr;
|
||||
struct snd_compr_file *data;
|
||||
|
||||
compr = device->device_data;
|
||||
scoped_guard(mutex, &compr->lock) {
|
||||
list_for_each_entry(data, &compr->open_list, list) {
|
||||
switch (data->stream.runtime->state) {
|
||||
case SNDRV_PCM_STATE_RUNNING:
|
||||
case SNDRV_PCM_STATE_DRAINING:
|
||||
case SNDRV_PCM_STATE_PAUSED:
|
||||
data->stream.ops->trigger(&data->stream,
|
||||
SNDRV_PCM_TRIGGER_STOP);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
data->stream.runtime->state = SNDRV_PCM_STATE_DISCONNECTED;
|
||||
wake_up(&data->stream.runtime->sleep);
|
||||
}
|
||||
}
|
||||
|
||||
snd_unregister_device(compr->dev);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1559,6 +1588,7 @@ int snd_compress_new(struct snd_card *card, int device,
|
|||
compr->device = device;
|
||||
compr->direction = dirn;
|
||||
mutex_init(&compr->lock);
|
||||
INIT_LIST_HEAD(&compr->open_list);
|
||||
|
||||
snd_compress_set_id(compr, id);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user