|
@@ -348,6 +348,40 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/* add a new kcontrol object; call with card->controls_rwsem locked */
|
|
|
+static int __snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
|
|
+{
|
|
|
+ struct snd_ctl_elem_id id;
|
|
|
+ unsigned int idx;
|
|
|
+ unsigned int count;
|
|
|
+
|
|
|
+ id = kcontrol->id;
|
|
|
+ if (id.index > UINT_MAX - kcontrol->count)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (snd_ctl_find_id(card, &id)) {
|
|
|
+ dev_err(card->dev,
|
|
|
+ "control %i:%i:%i:%s:%i is already present\n",
|
|
|
+ id.iface, id.device, id.subdevice, id.name, id.index);
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (snd_ctl_find_hole(card, kcontrol->count) < 0)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ list_add_tail(&kcontrol->list, &card->controls);
|
|
|
+ card->controls_count += kcontrol->count;
|
|
|
+ kcontrol->id.numid = card->last_numid + 1;
|
|
|
+ card->last_numid += kcontrol->count;
|
|
|
+
|
|
|
+ id = kcontrol->id;
|
|
|
+ count = kcontrol->count;
|
|
|
+ for (idx = 0; idx < count; idx++, id.index++, id.numid++)
|
|
|
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* snd_ctl_add - add the control instance to the card
|
|
|
* @card: the card instance
|
|
@@ -364,45 +398,18 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
|
|
|
*/
|
|
|
int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
|
|
{
|
|
|
- struct snd_ctl_elem_id id;
|
|
|
- unsigned int idx;
|
|
|
- unsigned int count;
|
|
|
int err = -EINVAL;
|
|
|
|
|
|
if (! kcontrol)
|
|
|
return err;
|
|
|
if (snd_BUG_ON(!card || !kcontrol->info))
|
|
|
goto error;
|
|
|
- id = kcontrol->id;
|
|
|
- if (id.index > UINT_MAX - kcontrol->count)
|
|
|
- goto error;
|
|
|
|
|
|
down_write(&card->controls_rwsem);
|
|
|
- if (snd_ctl_find_id(card, &id)) {
|
|
|
- up_write(&card->controls_rwsem);
|
|
|
- dev_err(card->dev, "control %i:%i:%i:%s:%i is already present\n",
|
|
|
- id.iface,
|
|
|
- id.device,
|
|
|
- id.subdevice,
|
|
|
- id.name,
|
|
|
- id.index);
|
|
|
- err = -EBUSY;
|
|
|
- goto error;
|
|
|
- }
|
|
|
- if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
|
|
|
- up_write(&card->controls_rwsem);
|
|
|
- err = -ENOMEM;
|
|
|
- goto error;
|
|
|
- }
|
|
|
- list_add_tail(&kcontrol->list, &card->controls);
|
|
|
- card->controls_count += kcontrol->count;
|
|
|
- kcontrol->id.numid = card->last_numid + 1;
|
|
|
- card->last_numid += kcontrol->count;
|
|
|
- id = kcontrol->id;
|
|
|
- count = kcontrol->count;
|
|
|
+ err = __snd_ctl_add(card, kcontrol);
|
|
|
up_write(&card->controls_rwsem);
|
|
|
- for (idx = 0; idx < count; idx++, id.index++, id.numid++)
|
|
|
- snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
|
|
|
+ if (err < 0)
|
|
|
+ goto error;
|
|
|
return 0;
|
|
|
|
|
|
error:
|
|
@@ -1361,9 +1368,12 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
|
|
kctl->tlv.c = snd_ctl_elem_user_tlv;
|
|
|
|
|
|
/* This function manage to free the instance on failure. */
|
|
|
- err = snd_ctl_add(card, kctl);
|
|
|
- if (err < 0)
|
|
|
- return err;
|
|
|
+ down_write(&card->controls_rwsem);
|
|
|
+ err = __snd_ctl_add(card, kctl);
|
|
|
+ if (err < 0) {
|
|
|
+ snd_ctl_free_one(kctl);
|
|
|
+ goto unlock;
|
|
|
+ }
|
|
|
offset = snd_ctl_get_ioff(kctl, &info->id);
|
|
|
snd_ctl_build_ioff(&info->id, kctl, offset);
|
|
|
/*
|
|
@@ -1374,10 +1384,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
|
|
|
* which locks the element.
|
|
|
*/
|
|
|
|
|
|
- down_write(&card->controls_rwsem);
|
|
|
card->user_ctl_count++;
|
|
|
- up_write(&card->controls_rwsem);
|
|
|
|
|
|
+ unlock:
|
|
|
+ up_write(&card->controls_rwsem);
|
|
|
return 0;
|
|
|
}
|
|
|
|