]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - sound/core/control.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
[karo-tx-linux.git] / sound / core / control.c
index a08ad57c49b6adf48a6fcc516dd02d62c159f406..5d98194bcad55b6963037d95d35743909517018a 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