]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - sound/core/control.c
Merge branch 'drm-core-next' of git://people.freedesktop.org/~airlied/linux
[karo-tx-linux.git] / sound / core / control.c
index a08ad57c49b6adf48a6fcc516dd02d62c159f406..f8c5be46451058ba5a7f25d9a81195fd02643f92 100644 (file)
@@ -365,6 +365,70 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
 
 EXPORT_SYMBOL(snd_ctl_add);
 
+/**
+ * snd_ctl_replace - replace the control instance of the card
+ * @card: the card instance
+ * @kcontrol: the control instance to replace
+ * @add_on_replace: add the control if not already added
+ *
+ * Replaces the given control.  If the given control does not exist
+ * and the add_on_replace flag is set, the control is added.  If the
+ * control exists, it is destroyed first.
+ *
+ * Returns zero if successful, or a negative error code on failure.
+ *
+ * It frees automatically the control which cannot be added or replaced.
+ */
+int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
+                   bool add_on_replace)
+{
+       struct snd_ctl_elem_id id;
+       unsigned int idx;
+       struct snd_kcontrol *old;
+       int ret;
+
+       if (!kcontrol)
+               return -EINVAL;
+       if (snd_BUG_ON(!card || !kcontrol->info)) {
+               ret = -EINVAL;
+               goto error;
+       }
+       id = kcontrol->id;
+       down_write(&card->controls_rwsem);
+       old = snd_ctl_find_id(card, &id);
+       if (!old) {
+               if (add_on_replace)
+                       goto add;
+               up_write(&card->controls_rwsem);
+               ret = -EINVAL;
+               goto error;
+       }
+       ret = snd_ctl_remove(card, old);
+       if (ret < 0) {
+               up_write(&card->controls_rwsem);
+               goto error;
+       }
+add:
+       if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
+               up_write(&card->controls_rwsem);
+               ret = -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;
+       up_write(&card->controls_rwsem);
+       for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
+               snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
+       return 0;
+
+error:
+       snd_ctl_free_one(kcontrol);
+       return ret;
+}
+EXPORT_SYMBOL(snd_ctl_replace);
+
 /**
  * snd_ctl_remove - remove the control from the card and release it
  * @card: the card instance
@@ -640,13 +704,12 @@ static int snd_ctl_elem_list(struct snd_card *card,
        struct snd_ctl_elem_list list;
        struct snd_kcontrol *kctl;
        struct snd_ctl_elem_id *dst, *id;
-       unsigned int offset, space, first, jidx;
+       unsigned int offset, space, jidx;
        
        if (copy_from_user(&list, _list, sizeof(list)))
                return -EFAULT;
        offset = list.offset;
        space = list.space;
-       first = 0;
        /* try limit maximum space */
        if (space > 16384)
                return -ENOMEM;