mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
ALSA: Make control API taking controls_rwsem consistently
A few ALSA control API helpers like snd_ctl_rename(), snd_ctl_remove() and snd_ctl_find_*() suppose the callers taking card->controls_rwsem. But it's error-prone and fragile. This patch set tries to change those API functions to take the card->controls>rwsem internally by themselves, so that the drivers don't need to take care of lockings. After applying this patch set, only a couple of places still touch card->controls_rwsem (which are OK-ish as they need for traversing the control linked list). Link: https://lore.kernel.org/r/20230718141304.1032-1-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de> -----BEGIN PGP SIGNATURE----- iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmS46rUOHHRpd2FpQHN1 c2UuZGUACgkQLtJE4w1nLE8tZRAAh24GODlDoY+KWCEo9ENkzUssWkfat174A5xE NJvW1N7cP7NeN8lQUbqvfB5DLTulBDb9RS0s42RcuqOt7/uKDlTV9Nx0exgyXINC Xxr5MaCsYuZxzCHy/9AxHchxgcksMkDVxugIQ4RmOhfof3lRA9O3OxLIdE+aHYhQ UOtrqnsoXlZXWjbi3OaT1KE2ilAXE/5f2P+fgoQ09ZQwyxAu43izeCkWJpBtWDuF /bHftmwXvHOIgiggeSJ0S0zrCPX5cPYzIcYusyucwyztj7CYIwGMyBncGw8ucyUr TjNhxQIZNDEyE3w0mre4X8rB3JLPlqaszqLKu6GsX8dwoAle5t1LPeG/6RhZxnD1 o6D9/HCu9VdVSSDFlQ87SZH81SV0ltqHFqUFX5XroAhYyBG9xe/z29AU5p2Qx2B4 saR/la384Bxedu/QpBM7pkqDZceKy4iNIGKVZXKu+1yd8Q5xbHNguU/RlXLM83iX /mcnO7/SDfI9m+hSgEXUZEl1pBW7wOWnTATAfjbr4ANNSwgzoVyS8a/86g3QjdvJ SlHysXDP+w5nf5QZd4wTMzKo6wjD5EMLie0FTCF9QvD5IMtAwVqTHYYoJDW85Qr0 gxovfYqjhZ05Aa87S+Gy154HUwLhRfhOaQp7wBpuHwlmYcFhw+0RnF6/RbZGEjMv VvP4PQ8= =V5+5 -----END PGP SIGNATURE----- Merge tag 'tags/ctl-lock-fixes-6.6' into for-next ALSA: Make control API taking controls_rwsem consistently A few ALSA control API helpers like snd_ctl_rename(), snd_ctl_remove() and snd_ctl_find_*() suppose the callers taking card->controls_rwsem. But it's error-prone and fragile. This patch set tries to change those API functions to take the card->controls>rwsem internally by themselves, so that the drivers don't need to take care of lockings. After applying this patch set, only a couple of places still touch card->controls_rwsem (which are OK-ish as they need for traversing the control linked list). Link: https://lore.kernel.org/r/20230718141304.1032-1-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
commit
f056f2fef3
@ -807,7 +807,6 @@ int gbaudio_register_module(struct gbaudio_module_info *module)
|
||||
{
|
||||
int ret;
|
||||
struct snd_soc_component *comp;
|
||||
struct snd_card *card;
|
||||
struct gbaudio_jack *jack = NULL;
|
||||
|
||||
if (!gbcodec) {
|
||||
@ -816,21 +815,20 @@ int gbaudio_register_module(struct gbaudio_module_info *module)
|
||||
}
|
||||
|
||||
comp = gbcodec->component;
|
||||
card = comp->card->snd_card;
|
||||
|
||||
down_write(&card->controls_rwsem);
|
||||
mutex_lock(&gbcodec->register_mutex);
|
||||
|
||||
if (module->num_dais) {
|
||||
dev_err(gbcodec->dev,
|
||||
"%d:DAIs not supported via gbcodec driver\n",
|
||||
module->num_dais);
|
||||
up_write(&card->controls_rwsem);
|
||||
mutex_unlock(&gbcodec->register_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = gbaudio_init_jack(module, comp->card);
|
||||
if (ret) {
|
||||
up_write(&card->controls_rwsem);
|
||||
mutex_unlock(&gbcodec->register_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -867,7 +865,7 @@ int gbaudio_register_module(struct gbaudio_module_info *module)
|
||||
ret = snd_soc_dapm_new_widgets(comp->card);
|
||||
dev_dbg(comp->dev, "Registered %s module\n", module->name);
|
||||
|
||||
up_write(&card->controls_rwsem);
|
||||
mutex_unlock(&gbcodec->register_mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(gbaudio_register_module);
|
||||
@ -935,13 +933,12 @@ static void gbaudio_codec_cleanup(struct gbaudio_module_info *module)
|
||||
void gbaudio_unregister_module(struct gbaudio_module_info *module)
|
||||
{
|
||||
struct snd_soc_component *comp = gbcodec->component;
|
||||
struct snd_card *card = comp->card->snd_card;
|
||||
struct gbaudio_jack *jack, *n;
|
||||
int mask;
|
||||
|
||||
dev_dbg(comp->dev, "Unregister %s module\n", module->name);
|
||||
|
||||
down_write(&card->controls_rwsem);
|
||||
mutex_lock(&gbcodec->register_mutex);
|
||||
mutex_lock(&gbcodec->lock);
|
||||
gbaudio_codec_cleanup(module);
|
||||
list_del(&module->list);
|
||||
@ -978,10 +975,8 @@ void gbaudio_unregister_module(struct gbaudio_module_info *module)
|
||||
dev_dbg(comp->dev, "Removing %d controls\n",
|
||||
module->num_controls);
|
||||
/* release control semaphore */
|
||||
up_write(&card->controls_rwsem);
|
||||
gbaudio_remove_component_controls(comp, module->controls,
|
||||
module->num_controls);
|
||||
down_write(&card->controls_rwsem);
|
||||
}
|
||||
if (module->dapm_widgets) {
|
||||
dev_dbg(comp->dev, "Removing %d widgets\n",
|
||||
@ -992,7 +987,7 @@ void gbaudio_unregister_module(struct gbaudio_module_info *module)
|
||||
|
||||
dev_dbg(comp->dev, "Unregistered %s module\n", module->name);
|
||||
|
||||
up_write(&card->controls_rwsem);
|
||||
mutex_unlock(&gbcodec->register_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(gbaudio_unregister_module);
|
||||
|
||||
@ -1012,6 +1007,7 @@ static int gbcodec_probe(struct snd_soc_component *comp)
|
||||
info->dev = comp->dev;
|
||||
INIT_LIST_HEAD(&info->module_list);
|
||||
mutex_init(&info->lock);
|
||||
mutex_init(&info->register_mutex);
|
||||
INIT_LIST_HEAD(&info->dai_list);
|
||||
|
||||
/* init dai_list used to maintain runtime stream info */
|
||||
|
@ -71,6 +71,7 @@ struct gbaudio_codec_info {
|
||||
/* to maintain runtime stream params for each DAI */
|
||||
struct list_head dai_list;
|
||||
struct mutex lock;
|
||||
struct mutex register_mutex;
|
||||
};
|
||||
|
||||
struct gbaudio_widget {
|
||||
|
@ -149,7 +149,6 @@ static int gbaudio_remove_controls(struct snd_card *card, struct device *dev,
|
||||
for (i = 0; i < num_controls; i++) {
|
||||
const struct snd_kcontrol_new *control = &controls[i];
|
||||
struct snd_ctl_elem_id id;
|
||||
struct snd_kcontrol *kctl;
|
||||
|
||||
if (prefix)
|
||||
snprintf(id.name, sizeof(id.name), "%s %s", prefix,
|
||||
@ -161,17 +160,10 @@ static int gbaudio_remove_controls(struct snd_card *card, struct device *dev,
|
||||
id.device = control->device;
|
||||
id.subdevice = control->subdevice;
|
||||
id.index = control->index;
|
||||
kctl = snd_ctl_find_id(card, &id);
|
||||
if (!kctl) {
|
||||
dev_err(dev, "Failed to find %s\n", control->name);
|
||||
continue;
|
||||
}
|
||||
err = snd_ctl_remove(card, kctl);
|
||||
if (err < 0) {
|
||||
err = snd_ctl_remove_id(card, &id);
|
||||
if (err < 0)
|
||||
dev_err(dev, "%d: Failed to remove %s\n", err,
|
||||
control->name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -181,11 +173,7 @@ int gbaudio_remove_component_controls(struct snd_soc_component *component,
|
||||
unsigned int num_controls)
|
||||
{
|
||||
struct snd_card *card = component->card->snd_card;
|
||||
int err;
|
||||
|
||||
down_write(&card->controls_rwsem);
|
||||
err = gbaudio_remove_controls(card, component->dev, controls,
|
||||
num_controls, component->name_prefix);
|
||||
up_write(&card->controls_rwsem);
|
||||
return err;
|
||||
return gbaudio_remove_controls(card, component->dev, controls,
|
||||
num_controls, component->name_prefix);
|
||||
}
|
||||
|
@ -140,8 +140,10 @@ int snd_ctl_remove_id(struct snd_card * card, struct snd_ctl_elem_id *id);
|
||||
int snd_ctl_rename_id(struct snd_card * card, struct snd_ctl_elem_id *src_id, struct snd_ctl_elem_id *dst_id);
|
||||
void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl, const char *name);
|
||||
int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, int active);
|
||||
struct snd_kcontrol *snd_ctl_find_numid(struct snd_card * card, unsigned int numid);
|
||||
struct snd_kcontrol *snd_ctl_find_id(struct snd_card * card, struct snd_ctl_elem_id *id);
|
||||
struct snd_kcontrol *snd_ctl_find_numid_locked(struct snd_card *card, unsigned int numid);
|
||||
struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid);
|
||||
struct snd_kcontrol *snd_ctl_find_id_locked(struct snd_card *card, const struct snd_ctl_elem_id *id);
|
||||
struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, const struct snd_ctl_elem_id *id);
|
||||
|
||||
int snd_ctl_create(struct snd_card *card);
|
||||
|
||||
|
@ -39,6 +39,9 @@ static LIST_HEAD(snd_control_compat_ioctls);
|
||||
#endif
|
||||
static struct snd_ctl_layer_ops *snd_ctl_layer;
|
||||
|
||||
static int snd_ctl_remove_locked(struct snd_card *card,
|
||||
struct snd_kcontrol *kcontrol);
|
||||
|
||||
static int snd_ctl_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
unsigned long flags;
|
||||
@ -466,11 +469,13 @@ static int __snd_ctl_add_replace(struct snd_card *card,
|
||||
struct snd_kcontrol *old;
|
||||
int err;
|
||||
|
||||
lockdep_assert_held_write(&card->controls_rwsem);
|
||||
|
||||
id = kcontrol->id;
|
||||
if (id.index > UINT_MAX - kcontrol->count)
|
||||
return -EINVAL;
|
||||
|
||||
old = snd_ctl_find_id(card, &id);
|
||||
old = snd_ctl_find_id_locked(card, &id);
|
||||
if (!old) {
|
||||
if (mode == CTL_REPLACE)
|
||||
return -EINVAL;
|
||||
@ -483,7 +488,7 @@ static int __snd_ctl_add_replace(struct snd_card *card,
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
err = snd_ctl_remove(card, old);
|
||||
err = snd_ctl_remove_locked(card, old);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
@ -575,6 +580,8 @@ static int __snd_ctl_remove(struct snd_card *card,
|
||||
{
|
||||
unsigned int idx;
|
||||
|
||||
lockdep_assert_held_write(&card->controls_rwsem);
|
||||
|
||||
if (snd_BUG_ON(!card || !kcontrol))
|
||||
return -EINVAL;
|
||||
list_del(&kcontrol->list);
|
||||
@ -589,20 +596,32 @@ static int __snd_ctl_remove(struct snd_card *card,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int snd_ctl_remove_locked(struct snd_card *card,
|
||||
struct snd_kcontrol *kcontrol)
|
||||
{
|
||||
return __snd_ctl_remove(card, kcontrol, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_ctl_remove - remove the control from the card and release it
|
||||
* @card: the card instance
|
||||
* @kcontrol: the control instance to remove
|
||||
*
|
||||
* Removes the control from the card and then releases the instance.
|
||||
* You don't need to call snd_ctl_free_one(). You must be in
|
||||
* the write lock - down_write(&card->controls_rwsem).
|
||||
* You don't need to call snd_ctl_free_one().
|
||||
*
|
||||
* Return: 0 if successful, or a negative error code on failure.
|
||||
*
|
||||
* Note that this function takes card->controls_rwsem lock internally.
|
||||
*/
|
||||
int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
||||
{
|
||||
return __snd_ctl_remove(card, kcontrol, true);
|
||||
int ret;
|
||||
|
||||
down_write(&card->controls_rwsem);
|
||||
ret = snd_ctl_remove_locked(card, kcontrol);
|
||||
up_write(&card->controls_rwsem);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_ctl_remove);
|
||||
|
||||
@ -622,12 +641,12 @@ int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
|
||||
int ret;
|
||||
|
||||
down_write(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_id(card, id);
|
||||
kctl = snd_ctl_find_id_locked(card, id);
|
||||
if (kctl == NULL) {
|
||||
up_write(&card->controls_rwsem);
|
||||
return -ENOENT;
|
||||
}
|
||||
ret = snd_ctl_remove(card, kctl);
|
||||
ret = snd_ctl_remove_locked(card, kctl);
|
||||
up_write(&card->controls_rwsem);
|
||||
return ret;
|
||||
}
|
||||
@ -651,7 +670,7 @@ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file,
|
||||
int idx, ret;
|
||||
|
||||
down_write(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_id(card, id);
|
||||
kctl = snd_ctl_find_id_locked(card, id);
|
||||
if (kctl == NULL) {
|
||||
ret = -ENOENT;
|
||||
goto error;
|
||||
@ -665,7 +684,7 @@ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file,
|
||||
ret = -EBUSY;
|
||||
goto error;
|
||||
}
|
||||
ret = snd_ctl_remove(card, kctl);
|
||||
ret = snd_ctl_remove_locked(card, kctl);
|
||||
error:
|
||||
up_write(&card->controls_rwsem);
|
||||
return ret;
|
||||
@ -692,7 +711,7 @@ int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
|
||||
int ret;
|
||||
|
||||
down_write(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_id(card, id);
|
||||
kctl = snd_ctl_find_id_locked(card, id);
|
||||
if (kctl == NULL) {
|
||||
ret = -ENOENT;
|
||||
goto unlock;
|
||||
@ -746,7 +765,7 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
|
||||
int saved_numid;
|
||||
|
||||
down_write(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_id(card, src_id);
|
||||
kctl = snd_ctl_find_id_locked(card, src_id);
|
||||
if (kctl == NULL) {
|
||||
up_write(&card->controls_rwsem);
|
||||
return -ENOENT;
|
||||
@ -769,11 +788,12 @@ EXPORT_SYMBOL(snd_ctl_rename_id);
|
||||
*
|
||||
* Renames the specified control on the card to the new name.
|
||||
*
|
||||
* Make sure to take the control write lock - down_write(&card->controls_rwsem).
|
||||
* Note that this function takes card->controls_rwsem lock internally.
|
||||
*/
|
||||
void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl,
|
||||
const char *name)
|
||||
{
|
||||
down_write(&card->controls_rwsem);
|
||||
remove_hash_entries(card, kctl);
|
||||
|
||||
if (strscpy(kctl->id.name, name, sizeof(kctl->id.name)) < 0)
|
||||
@ -781,6 +801,7 @@ void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl,
|
||||
name, kctl->id.name);
|
||||
|
||||
add_hash_entries(card, kctl);
|
||||
up_write(&card->controls_rwsem);
|
||||
}
|
||||
EXPORT_SYMBOL(snd_ctl_rename);
|
||||
|
||||
@ -799,7 +820,7 @@ snd_ctl_find_numid_slow(struct snd_card *card, unsigned int numid)
|
||||
#endif /* !CONFIG_SND_CTL_FAST_LOOKUP */
|
||||
|
||||
/**
|
||||
* snd_ctl_find_numid - find the control instance with the given number-id
|
||||
* snd_ctl_find_numid_locked - find the control instance with the given number-id
|
||||
* @card: the card instance
|
||||
* @numid: the number-id to search
|
||||
*
|
||||
@ -809,22 +830,46 @@ snd_ctl_find_numid_slow(struct snd_card *card, unsigned int numid)
|
||||
* (if the race condition can happen).
|
||||
*
|
||||
* Return: The pointer of the instance if found, or %NULL if not.
|
||||
*
|
||||
*/
|
||||
struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid)
|
||||
struct snd_kcontrol *
|
||||
snd_ctl_find_numid_locked(struct snd_card *card, unsigned int numid)
|
||||
{
|
||||
if (snd_BUG_ON(!card || !numid))
|
||||
return NULL;
|
||||
lockdep_assert_held(&card->controls_rwsem);
|
||||
#ifdef CONFIG_SND_CTL_FAST_LOOKUP
|
||||
return xa_load(&card->ctl_numids, numid);
|
||||
#else
|
||||
return snd_ctl_find_numid_slow(card, numid);
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(snd_ctl_find_numid_locked);
|
||||
|
||||
/**
|
||||
* snd_ctl_find_numid - find the control instance with the given number-id
|
||||
* @card: the card instance
|
||||
* @numid: the number-id to search
|
||||
*
|
||||
* Finds the control instance with the given number-id from the card.
|
||||
*
|
||||
* Return: The pointer of the instance if found, or %NULL if not.
|
||||
*
|
||||
* Note that this function takes card->controls_rwsem lock internally.
|
||||
*/
|
||||
struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card,
|
||||
unsigned int numid)
|
||||
{
|
||||
struct snd_kcontrol *kctl;
|
||||
|
||||
down_read(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_numid_locked(card, numid);
|
||||
up_read(&card->controls_rwsem);
|
||||
return kctl;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_ctl_find_numid);
|
||||
|
||||
/**
|
||||
* snd_ctl_find_id - find the control instance with the given id
|
||||
* snd_ctl_find_id_locked - find the control instance with the given id
|
||||
* @card: the card instance
|
||||
* @id: the id to search
|
||||
*
|
||||
@ -834,17 +879,17 @@ EXPORT_SYMBOL(snd_ctl_find_numid);
|
||||
* (if the race condition can happen).
|
||||
*
|
||||
* Return: The pointer of the instance if found, or %NULL if not.
|
||||
*
|
||||
*/
|
||||
struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
|
||||
struct snd_ctl_elem_id *id)
|
||||
struct snd_kcontrol *snd_ctl_find_id_locked(struct snd_card *card,
|
||||
const struct snd_ctl_elem_id *id)
|
||||
{
|
||||
struct snd_kcontrol *kctl;
|
||||
|
||||
if (snd_BUG_ON(!card || !id))
|
||||
return NULL;
|
||||
lockdep_assert_held(&card->controls_rwsem);
|
||||
if (id->numid != 0)
|
||||
return snd_ctl_find_numid(card, id->numid);
|
||||
return snd_ctl_find_numid_locked(card, id->numid);
|
||||
#ifdef CONFIG_SND_CTL_FAST_LOOKUP
|
||||
kctl = xa_load(&card->ctl_hash, get_ctl_id_hash(id));
|
||||
if (kctl && elem_id_matches(kctl, id))
|
||||
@ -859,6 +904,29 @@ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_ctl_find_id_locked);
|
||||
|
||||
/**
|
||||
* snd_ctl_find_id - find the control instance with the given id
|
||||
* @card: the card instance
|
||||
* @id: the id to search
|
||||
*
|
||||
* Finds the control instance with the given id from the card.
|
||||
*
|
||||
* Return: The pointer of the instance if found, or %NULL if not.
|
||||
*
|
||||
* Note that this function takes card->controls_rwsem lock internally.
|
||||
*/
|
||||
struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
|
||||
const struct snd_ctl_elem_id *id)
|
||||
{
|
||||
struct snd_kcontrol *kctl;
|
||||
|
||||
down_read(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_id_locked(card, id);
|
||||
up_read(&card->controls_rwsem);
|
||||
return kctl;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_ctl_find_id);
|
||||
|
||||
static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
|
||||
@ -1173,7 +1241,7 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
|
||||
int result;
|
||||
|
||||
down_read(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_id(card, &info->id);
|
||||
kctl = snd_ctl_find_id_locked(card, &info->id);
|
||||
if (kctl == NULL)
|
||||
result = -ENOENT;
|
||||
else
|
||||
@ -1212,7 +1280,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
|
||||
int ret;
|
||||
|
||||
down_read(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_id(card, &control->id);
|
||||
kctl = snd_ctl_find_id_locked(card, &control->id);
|
||||
if (kctl == NULL) {
|
||||
ret = -ENOENT;
|
||||
goto unlock;
|
||||
@ -1289,7 +1357,7 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
|
||||
int result;
|
||||
|
||||
down_write(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_id(card, &control->id);
|
||||
kctl = snd_ctl_find_id_locked(card, &control->id);
|
||||
if (kctl == NULL) {
|
||||
up_write(&card->controls_rwsem);
|
||||
return -ENOENT;
|
||||
@ -1370,7 +1438,7 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file,
|
||||
if (copy_from_user(&id, _id, sizeof(id)))
|
||||
return -EFAULT;
|
||||
down_write(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_id(card, &id);
|
||||
kctl = snd_ctl_find_id_locked(card, &id);
|
||||
if (kctl == NULL) {
|
||||
result = -ENOENT;
|
||||
} else {
|
||||
@ -1398,7 +1466,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
|
||||
if (copy_from_user(&id, _id, sizeof(id)))
|
||||
return -EFAULT;
|
||||
down_write(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_id(card, &id);
|
||||
kctl = snd_ctl_find_id_locked(card, &id);
|
||||
if (kctl == NULL) {
|
||||
result = -ENOENT;
|
||||
} else {
|
||||
@ -1507,6 +1575,8 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
|
||||
int i;
|
||||
int change;
|
||||
|
||||
lockdep_assert_held_write(&ue->card->controls_rwsem);
|
||||
|
||||
if (size > 1024 * 128) /* sane value */
|
||||
return -EINVAL;
|
||||
|
||||
@ -1583,6 +1653,8 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue)
|
||||
unsigned int i;
|
||||
const uintptr_t user_ptrval = ue->info.value.enumerated.names_ptr;
|
||||
|
||||
lockdep_assert_held_write(&ue->card->controls_rwsem);
|
||||
|
||||
buf_len = ue->info.value.enumerated.names_length;
|
||||
if (buf_len > 64 * 1024)
|
||||
return -EINVAL;
|
||||
@ -1887,6 +1959,8 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
|
||||
struct snd_ctl_elem_id id;
|
||||
struct snd_kcontrol_volatile *vd;
|
||||
|
||||
lockdep_assert_held(&file->card->controls_rwsem);
|
||||
|
||||
if (copy_from_user(&header, buf, sizeof(header)))
|
||||
return -EFAULT;
|
||||
|
||||
@ -1900,7 +1974,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
|
||||
container_size = header.length;
|
||||
container = buf->tlv;
|
||||
|
||||
kctl = snd_ctl_find_numid(file->card, header.numid);
|
||||
kctl = snd_ctl_find_numid_locked(file->card, header.numid);
|
||||
if (kctl == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
|
@ -173,7 +173,7 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
|
||||
int err;
|
||||
|
||||
down_read(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_id(card, id);
|
||||
kctl = snd_ctl_find_id_locked(card, id);
|
||||
if (! kctl) {
|
||||
up_read(&card->controls_rwsem);
|
||||
return -ENOENT;
|
||||
|
@ -251,7 +251,7 @@ static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id,
|
||||
card = snd_card_ref(card_number);
|
||||
if (card) {
|
||||
down_write(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_id(card, id);
|
||||
kctl = snd_ctl_find_id_locked(card, id);
|
||||
if (kctl) {
|
||||
ioff = snd_ctl_get_ioff(kctl, id);
|
||||
vd = &kctl->vd[ioff];
|
||||
|
@ -66,12 +66,10 @@ static int snd_jack_dev_free(struct snd_device *device)
|
||||
struct snd_card *card = device->card;
|
||||
struct snd_jack_kctl *jack_kctl, *tmp_jack_kctl;
|
||||
|
||||
down_write(&card->controls_rwsem);
|
||||
list_for_each_entry_safe(jack_kctl, tmp_jack_kctl, &jack->kctl_list, list) {
|
||||
list_del_init(&jack_kctl->list);
|
||||
snd_ctl_remove(card, jack_kctl->kctl);
|
||||
}
|
||||
up_write(&card->controls_rwsem);
|
||||
|
||||
if (jack->private_free)
|
||||
jack->private_free(jack);
|
||||
|
@ -524,7 +524,7 @@ static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, c
|
||||
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
||||
strscpy(id.name, name, sizeof(id.name));
|
||||
id.index = index;
|
||||
return snd_ctl_find_id(card, &id);
|
||||
return snd_ctl_find_id_locked(card, &id);
|
||||
}
|
||||
|
||||
static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
|
||||
@ -540,7 +540,7 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
|
||||
if (numid == ID_UNKNOWN)
|
||||
return;
|
||||
down_read(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_numid(card, numid);
|
||||
kctl = snd_ctl_find_numid_locked(card, numid);
|
||||
if (!kctl) {
|
||||
up_read(&card->controls_rwsem);
|
||||
return;
|
||||
@ -579,7 +579,7 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
|
||||
if (numid == ID_UNKNOWN)
|
||||
return;
|
||||
down_read(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_numid(card, numid);
|
||||
kctl = snd_ctl_find_numid_locked(card, numid);
|
||||
if (!kctl) {
|
||||
up_read(&card->controls_rwsem);
|
||||
return;
|
||||
@ -645,7 +645,7 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
|
||||
if (numid == ID_UNKNOWN)
|
||||
return;
|
||||
down_read(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_numid(card, numid);
|
||||
kctl = snd_ctl_find_numid_locked(card, numid);
|
||||
if (!kctl) {
|
||||
up_read(&card->controls_rwsem);
|
||||
return;
|
||||
@ -688,7 +688,7 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
|
||||
if (numid == ID_UNKNOWN)
|
||||
return;
|
||||
down_read(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_numid(card, numid);
|
||||
kctl = snd_ctl_find_numid_locked(card, numid);
|
||||
if (!kctl) {
|
||||
up_read(&card->controls_rwsem);
|
||||
return;
|
||||
|
@ -814,9 +814,7 @@ static void free_chmap(struct snd_pcm_str *pstr)
|
||||
if (pstr->chmap_kctl) {
|
||||
struct snd_card *card = pstr->pcm->card;
|
||||
|
||||
down_write(&card->controls_rwsem);
|
||||
snd_ctl_remove(card, pstr->chmap_kctl);
|
||||
up_write(&card->controls_rwsem);
|
||||
pstr->chmap_kctl = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -1040,10 +1040,8 @@ snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu)
|
||||
|
||||
__error:
|
||||
for (i = 0; i < EMU8000_NUM_CONTROLS; i++) {
|
||||
down_write(&card->controls_rwsem);
|
||||
if (emu->controls[i])
|
||||
snd_ctl_remove(card, emu->controls[i]);
|
||||
up_write(&card->controls_rwsem);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
@ -1080,7 +1080,6 @@ static void snd_sb_qsound_destroy(struct snd_sb_csp * p)
|
||||
|
||||
card = p->chip->card;
|
||||
|
||||
down_write(&card->controls_rwsem);
|
||||
if (p->qsound_switch) {
|
||||
snd_ctl_remove(card, p->qsound_switch);
|
||||
p->qsound_switch = NULL;
|
||||
@ -1089,7 +1088,6 @@ static void snd_sb_qsound_destroy(struct snd_sb_csp * p)
|
||||
snd_ctl_remove(card, p->qsound_space);
|
||||
p->qsound_space = NULL;
|
||||
}
|
||||
up_write(&card->controls_rwsem);
|
||||
|
||||
/* cancel pending transfer of QSound parameters */
|
||||
spin_lock_irqsave (&p->q_lock, flags);
|
||||
|
@ -793,13 +793,10 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
|
||||
if (snd_emu10k1_look_for_ctl(emu, &gctl->id))
|
||||
continue;
|
||||
gctl_id = (struct snd_ctl_elem_id *)&gctl->id;
|
||||
down_read(&emu->card->controls_rwsem);
|
||||
if (snd_ctl_find_id(emu->card, gctl_id)) {
|
||||
up_read(&emu->card->controls_rwsem);
|
||||
err = -EEXIST;
|
||||
goto __error;
|
||||
}
|
||||
up_read(&emu->card->controls_rwsem);
|
||||
if (gctl_id->iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
|
||||
gctl_id->iface != SNDRV_CTL_ELEM_IFACE_PCM) {
|
||||
err = -EINVAL;
|
||||
@ -971,11 +968,9 @@ static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu,
|
||||
in_kernel);
|
||||
if (err < 0)
|
||||
return err;
|
||||
down_write(&card->controls_rwsem);
|
||||
ctl = snd_emu10k1_look_for_ctl(emu, &id);
|
||||
if (ctl)
|
||||
snd_ctl_remove(card, ctl->kcontrol);
|
||||
up_write(&card->controls_rwsem);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1769,10 +1769,8 @@ void snd_hda_ctls_clear(struct hda_codec *codec)
|
||||
int i;
|
||||
struct hda_nid_item *items = codec->mixers.list;
|
||||
|
||||
down_write(&codec->card->controls_rwsem);
|
||||
for (i = 0; i < codec->mixers.used; i++)
|
||||
snd_ctl_remove(codec->card, items[i].kctl);
|
||||
up_write(&codec->card->controls_rwsem);
|
||||
snd_array_free(&codec->mixers);
|
||||
snd_array_free(&codec->nids);
|
||||
}
|
||||
|
@ -386,7 +386,6 @@ static int mchp_pdmc_open(struct snd_soc_component *component,
|
||||
for (i = 0; i < ARRAY_SIZE(mchp_pdmc_snd_controls); i++) {
|
||||
const struct snd_kcontrol_new *control = &mchp_pdmc_snd_controls[i];
|
||||
struct snd_ctl_elem_id id;
|
||||
struct snd_kcontrol *kctl;
|
||||
int err;
|
||||
|
||||
if (component->name_prefix)
|
||||
@ -400,17 +399,10 @@ static int mchp_pdmc_open(struct snd_soc_component *component,
|
||||
id.device = control->device;
|
||||
id.subdevice = control->subdevice;
|
||||
id.index = control->index;
|
||||
kctl = snd_ctl_find_id(component->card->snd_card, &id);
|
||||
if (!kctl) {
|
||||
dev_err(component->dev, "Failed to find %s\n", control->name);
|
||||
continue;
|
||||
}
|
||||
err = snd_ctl_remove(component->card->snd_card, kctl);
|
||||
if (err < 0) {
|
||||
err = snd_ctl_remove_id(component->card->snd_card, &id);
|
||||
if (err < 0)
|
||||
dev_err(component->dev, "%d: Failed to remove %s\n", err,
|
||||
control->name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -669,36 +669,19 @@ static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp,
|
||||
struct sigmadsp_control *ctrl, unsigned int samplerate_mask)
|
||||
{
|
||||
struct snd_card *card = sigmadsp->component->card->snd_card;
|
||||
struct snd_kcontrol_volatile *vd;
|
||||
struct snd_ctl_elem_id id;
|
||||
bool active;
|
||||
bool changed = false;
|
||||
int changed;
|
||||
|
||||
active = sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask);
|
||||
|
||||
down_write(&card->controls_rwsem);
|
||||
if (!ctrl->kcontrol) {
|
||||
up_write(&card->controls_rwsem);
|
||||
if (!ctrl->kcontrol)
|
||||
return;
|
||||
}
|
||||
|
||||
id = ctrl->kcontrol->id;
|
||||
vd = &ctrl->kcontrol->vd[0];
|
||||
if (active == (bool)(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)) {
|
||||
vd->access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
||||
changed = true;
|
||||
}
|
||||
up_write(&card->controls_rwsem);
|
||||
|
||||
if (active && changed) {
|
||||
changed = snd_ctl_activate_id(card, &ctrl->kcontrol->id, active);
|
||||
if (active && changed > 0) {
|
||||
mutex_lock(&sigmadsp->lock);
|
||||
if (ctrl->cached)
|
||||
sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache);
|
||||
mutex_unlock(&sigmadsp->lock);
|
||||
}
|
||||
|
||||
if (changed)
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2564,7 +2564,6 @@ EXPORT_SYMBOL_GPL(snd_soc_tplg_component_load);
|
||||
/* remove dynamic controls from the component driver */
|
||||
int snd_soc_tplg_component_remove(struct snd_soc_component *comp)
|
||||
{
|
||||
struct snd_card *card = comp->card->snd_card;
|
||||
struct snd_soc_dobj *dobj, *next_dobj;
|
||||
int pass;
|
||||
|
||||
@ -2572,7 +2571,6 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp)
|
||||
for (pass = SOC_TPLG_PASS_END; pass >= SOC_TPLG_PASS_START; pass--) {
|
||||
|
||||
/* remove mixer controls */
|
||||
down_write(&card->controls_rwsem);
|
||||
list_for_each_entry_safe(dobj, next_dobj, &comp->dobj_list,
|
||||
list) {
|
||||
|
||||
@ -2607,7 +2605,6 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp)
|
||||
break;
|
||||
}
|
||||
}
|
||||
up_write(&card->controls_rwsem);
|
||||
}
|
||||
|
||||
/* let caller know if FW can be freed when no objects are left */
|
||||
|
Loading…
Reference in New Issue
Block a user