diff options
Diffstat (limited to 'sound/core/control.c')
-rw-r--r-- | sound/core/control.c | 68 |
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 | ||
280 | EXPORT_SYMBOL(snd_ctl_free_one); | 280 | EXPORT_SYMBOL(snd_ctl_free_one); |
281 | 281 | ||
282 | static unsigned int snd_ctl_hole_check(struct snd_card *card, | 282 | static 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 | ||
297 | static int snd_ctl_find_hole(struct snd_card *card, unsigned int count) | 297 | static 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 | */ | ||
477 | int 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 | } | ||
510 | EXPORT_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 |