diff --git a/include/sound/control.h b/include/sound/control.h index 37e9c545503e..8e24b668d796 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -289,7 +289,7 @@ snd_ctl_add_follower_uncached(struct snd_kcontrol *master, return _snd_ctl_add_follower(master, follower, SND_CTL_FOLLOWER_NEED_UPDATE); } -int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kctl, +int snd_ctl_add_vmaster_hook(struct snd_card *card, struct snd_kcontrol *kctl, void (*hook)(void *private_data, int), void *private_data); void snd_ctl_sync_vmaster(struct snd_kcontrol *kctl, bool hook_only); diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index cd3dcaaf9f72..3d57182031d9 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c @@ -463,6 +463,7 @@ EXPORT_SYMBOL(snd_ctl_make_virtual_master); /** * snd_ctl_add_vmaster_hook - Add a hook to a vmaster control + * @card: the card instance * @kcontrol: vmaster kctl element * @hook: the hook function * @private_data: the private_data pointer to be saved @@ -470,13 +471,17 @@ EXPORT_SYMBOL(snd_ctl_make_virtual_master); * Adds the given hook to the vmaster control element so that it's called * at each time when the value is changed. * + * Takes the card's controls_rwsem lock internally. + * * Return: Zero. */ -int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol, +int snd_ctl_add_vmaster_hook(struct snd_card *card, struct snd_kcontrol *kcontrol, void (*hook)(void *private_data, int), void *private_data) { struct link_master *master = snd_kcontrol_chip(kcontrol); + + guard(rwsem_write)(&card->controls_rwsem); master->hook = hook; master->hook_private_data = private_data; return 0; diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c index 18838a45e6f7..31e5fad78b0f 100644 --- a/sound/hda/common/codec.c +++ b/sound/hda/common/codec.c @@ -2025,7 +2025,7 @@ int snd_hda_add_vmaster_hook(struct hda_codec *codec, if (!hook->hook || !hook->sw_kctl) return 0; hook->codec = codec; - snd_ctl_add_vmaster_hook(hook->sw_kctl, vmaster_hook, hook); + snd_ctl_add_vmaster_hook(codec->card, hook->sw_kctl, vmaster_hook, hook); return 0; } EXPORT_SYMBOL_GPL(snd_hda_add_vmaster_hook);