aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/control.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/control.c')
-rw-r--r--sound/core/control.c68
1 files changed, 56 insertions, 12 deletions
diff --git a/sound/core/control.c b/sound/core/control.c
index 9ce00ed20fba..a08ad57c49b6 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -279,33 +279,31 @@ void snd_ctl_free_one(struct snd_kcontrol *kcontrol)
279 279
280EXPORT_SYMBOL(snd_ctl_free_one); 280EXPORT_SYMBOL(snd_ctl_free_one);
281 281
282static unsigned int snd_ctl_hole_check(struct snd_card *card, 282static bool snd_ctl_remove_numid_conflict(struct snd_card *card,
283 unsigned int count) 283 unsigned int count)
284{ 284{
285 struct snd_kcontrol *kctl; 285 struct snd_kcontrol *kctl;
286 286
287 list_for_each_entry(kctl, &card->controls, list) { 287 list_for_each_entry(kctl, &card->controls, list) {
288 if ((kctl->id.numid <= card->last_numid && 288 if (kctl->id.numid < card->last_numid + 1 + count &&
289 kctl->id.numid + kctl->count > card->last_numid) || 289 kctl->id.numid + kctl->count > card->last_numid + 1) {
290 (kctl->id.numid <= card->last_numid + count - 1 && 290 card->last_numid = kctl->id.numid + kctl->count - 1;
291 kctl->id.numid + kctl->count > card->last_numid + count - 1)) 291 return true;
292 return card->last_numid = kctl->id.numid + kctl->count - 1; 292 }
293 } 293 }
294 return card->last_numid; 294 return false;
295} 295}
296 296
297static int snd_ctl_find_hole(struct snd_card *card, unsigned int count) 297static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
298{ 298{
299 unsigned int last_numid, iter = 100000; 299 unsigned int iter = 100000;
300 300
301 last_numid = card->last_numid; 301 while (snd_ctl_remove_numid_conflict(card, count)) {
302 while (last_numid != snd_ctl_hole_check(card, count)) {
303 if (--iter == 0) { 302 if (--iter == 0) {
304 /* this situation is very unlikely */ 303 /* this situation is very unlikely */
305 snd_printk(KERN_ERR "unable to allocate new control numid\n"); 304 snd_printk(KERN_ERR "unable to allocate new control numid\n");
306 return -ENOMEM; 305 return -ENOMEM;
307 } 306 }
308 last_numid = card->last_numid;
309 } 307 }
310 return 0; 308 return 0;
311} 309}
@@ -466,6 +464,52 @@ error:
466} 464}
467 465
468/** 466/**
467 * snd_ctl_activate_id - activate/inactivate the control of the given id
468 * @card: the card instance
469 * @id: the control id to activate/inactivate
470 * @active: non-zero to activate
471 *
472 * Finds the control instance with the given id, and activate or
473 * inactivate the control together with notification, if changed.
474 *
475 * Returns 0 if unchanged, 1 if changed, or a negative error code on failure.
476 */
477int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
478 int active)
479{
480 struct snd_kcontrol *kctl;
481 struct snd_kcontrol_volatile *vd;
482 unsigned int index_offset;
483 int ret;
484
485 down_write(&card->controls_rwsem);
486 kctl = snd_ctl_find_id(card, id);
487 if (kctl == NULL) {
488 ret = -ENOENT;
489 goto unlock;
490 }
491 index_offset = snd_ctl_get_ioff(kctl, &kctl->id);
492 vd = &kctl->vd[index_offset];
493 ret = 0;
494 if (active) {
495 if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE))
496 goto unlock;
497 vd->access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
498 } else {
499 if (vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)
500 goto unlock;
501 vd->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
502 }
503 ret = 1;
504 unlock:
505 up_write(&card->controls_rwsem);
506 if (ret > 0)
507 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, id);
508 return ret;
509}
510EXPORT_SYMBOL_GPL(snd_ctl_activate_id);
511
512/**
469 * snd_ctl_rename_id - replace the id of a control on the card 513 * snd_ctl_rename_id - replace the id of a control on the card
470 * @card: the card instance 514 * @card: the card instance
471 * @src_id: the old id 515 * @src_id: the old id