sys_swapon: fix inode locking
[pandora-kernel.git] / sound / core / control.c
index 9ce00ed..a08ad57 100644 (file)
@@ -279,33 +279,31 @@ void snd_ctl_free_one(struct snd_kcontrol *kcontrol)
 
 EXPORT_SYMBOL(snd_ctl_free_one);
 
-static unsigned int snd_ctl_hole_check(struct snd_card *card,
-                                      unsigned int count)
+static bool snd_ctl_remove_numid_conflict(struct snd_card *card,
+                                         unsigned int count)
 {
        struct snd_kcontrol *kctl;
 
        list_for_each_entry(kctl, &card->controls, list) {
-               if ((kctl->id.numid <= card->last_numid &&
-                    kctl->id.numid + kctl->count > card->last_numid) ||
-                   (kctl->id.numid <= card->last_numid + count - 1 &&
-                    kctl->id.numid + kctl->count > card->last_numid + count - 1))
-                       return card->last_numid = kctl->id.numid + kctl->count - 1;
+               if (kctl->id.numid < card->last_numid + 1 + count &&
+                   kctl->id.numid + kctl->count > card->last_numid + 1) {
+                       card->last_numid = kctl->id.numid + kctl->count - 1;
+                       return true;
+               }
        }
-       return card->last_numid;
+       return false;
 }
 
 static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
 {
-       unsigned int last_numid, iter = 100000;
+       unsigned int iter = 100000;
 
-       last_numid = card->last_numid;
-       while (last_numid != snd_ctl_hole_check(card, count)) {
+       while (snd_ctl_remove_numid_conflict(card, count)) {
                if (--iter == 0) {
                        /* this situation is very unlikely */
                        snd_printk(KERN_ERR "unable to allocate new control numid\n");
                        return -ENOMEM;
                }
-               last_numid = card->last_numid;
        }
        return 0;
 }
@@ -465,6 +463,52 @@ error:
        return ret;
 }
 
+/**
+ * snd_ctl_activate_id - activate/inactivate the control of the given id
+ * @card: the card instance
+ * @id: the control id to activate/inactivate
+ * @active: non-zero to activate
+ *
+ * Finds the control instance with the given id, and activate or
+ * inactivate the control together with notification, if changed.
+ *
+ * Returns 0 if unchanged, 1 if changed, or a negative error code on failure.
+ */
+int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
+                       int active)
+{
+       struct snd_kcontrol *kctl;
+       struct snd_kcontrol_volatile *vd;
+       unsigned int index_offset;
+       int ret;
+
+       down_write(&card->controls_rwsem);
+       kctl = snd_ctl_find_id(card, id);
+       if (kctl == NULL) {
+               ret = -ENOENT;
+               goto unlock;
+       }
+       index_offset = snd_ctl_get_ioff(kctl, &kctl->id);
+       vd = &kctl->vd[index_offset];
+       ret = 0;
+       if (active) {
+               if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE))
+                       goto unlock;
+               vd->access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+       } else {
+               if (vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)
+                       goto unlock;
+               vd->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+       }
+       ret = 1;
+ unlock:
+       up_write(&card->controls_rwsem);
+       if (ret > 0)
+               snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, id);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_ctl_activate_id);
+
 /**
  * snd_ctl_rename_id - replace the id of a control on the card
  * @card: the card instance