aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/control.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /sound/core/control.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'sound/core/control.c')
-rw-r--r--sound/core/control.c163
1 files changed, 148 insertions, 15 deletions
diff --git a/sound/core/control.c b/sound/core/control.c
index 45a818002d99..f8c5be464510 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}
@@ -368,6 +366,70 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
368EXPORT_SYMBOL(snd_ctl_add); 366EXPORT_SYMBOL(snd_ctl_add);
369 367
370/** 368/**
369 * snd_ctl_replace - replace the control instance of the card
370 * @card: the card instance
371 * @kcontrol: the control instance to replace
372 * @add_on_replace: add the control if not already added
373 *
374 * Replaces the given control. If the given control does not exist
375 * and the add_on_replace flag is set, the control is added. If the
376 * control exists, it is destroyed first.
377 *
378 * Returns zero if successful, or a negative error code on failure.
379 *
380 * It frees automatically the control which cannot be added or replaced.
381 */
382int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
383 bool add_on_replace)
384{
385 struct snd_ctl_elem_id id;
386 unsigned int idx;
387 struct snd_kcontrol *old;
388 int ret;
389
390 if (!kcontrol)
391 return -EINVAL;
392 if (snd_BUG_ON(!card || !kcontrol->info)) {
393 ret = -EINVAL;
394 goto error;
395 }
396 id = kcontrol->id;
397 down_write(&card->controls_rwsem);
398 old = snd_ctl_find_id(card, &id);
399 if (!old) {
400 if (add_on_replace)
401 goto add;
402 up_write(&card->controls_rwsem);
403 ret = -EINVAL;
404 goto error;
405 }
406 ret = snd_ctl_remove(card, old);
407 if (ret < 0) {
408 up_write(&card->controls_rwsem);
409 goto error;
410 }
411add:
412 if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
413 up_write(&card->controls_rwsem);
414 ret = -ENOMEM;
415 goto error;
416 }
417 list_add_tail(&kcontrol->list, &card->controls);
418 card->controls_count += kcontrol->count;
419 kcontrol->id.numid = card->last_numid + 1;
420 card->last_numid += kcontrol->count;
421 up_write(&card->controls_rwsem);
422 for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
423 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
424 return 0;
425
426error:
427 snd_ctl_free_one(kcontrol);
428 return ret;
429}
430EXPORT_SYMBOL(snd_ctl_replace);
431
432/**
371 * snd_ctl_remove - remove the control from the card and release it 433 * snd_ctl_remove - remove the control from the card and release it
372 * @card: the card instance 434 * @card: the card instance
373 * @kcontrol: the control instance to remove 435 * @kcontrol: the control instance to remove
@@ -466,6 +528,52 @@ error:
466} 528}
467 529
468/** 530/**
531 * snd_ctl_activate_id - activate/inactivate the control of the given id
532 * @card: the card instance
533 * @id: the control id to activate/inactivate
534 * @active: non-zero to activate
535 *
536 * Finds the control instance with the given id, and activate or
537 * inactivate the control together with notification, if changed.
538 *
539 * Returns 0 if unchanged, 1 if changed, or a negative error code on failure.
540 */
541int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
542 int active)
543{
544 struct snd_kcontrol *kctl;
545 struct snd_kcontrol_volatile *vd;
546 unsigned int index_offset;
547 int ret;
548
549 down_write(&card->controls_rwsem);
550 kctl = snd_ctl_find_id(card, id);
551 if (kctl == NULL) {
552 ret = -ENOENT;
553 goto unlock;
554 }
555 index_offset = snd_ctl_get_ioff(kctl, &kctl->id);
556 vd = &kctl->vd[index_offset];
557 ret = 0;
558 if (active) {
559 if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE))
560 goto unlock;
561 vd->access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
562 } else {
563 if (vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)
564 goto unlock;
565 vd->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
566 }
567 ret = 1;
568 unlock:
569 up_write(&card->controls_rwsem);
570 if (ret > 0)
571 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, id);
572 return ret;
573}
574EXPORT_SYMBOL_GPL(snd_ctl_activate_id);
575
576/**
469 * snd_ctl_rename_id - replace the id of a control on the card 577 * snd_ctl_rename_id - replace the id of a control on the card
470 * @card: the card instance 578 * @card: the card instance
471 * @src_id: the old id 579 * @src_id: the old id
@@ -596,13 +704,12 @@ static int snd_ctl_elem_list(struct snd_card *card,
596 struct snd_ctl_elem_list list; 704 struct snd_ctl_elem_list list;
597 struct snd_kcontrol *kctl; 705 struct snd_kcontrol *kctl;
598 struct snd_ctl_elem_id *dst, *id; 706 struct snd_ctl_elem_id *dst, *id;
599 unsigned int offset, space, first, jidx; 707 unsigned int offset, space, jidx;
600 708
601 if (copy_from_user(&list, _list, sizeof(list))) 709 if (copy_from_user(&list, _list, sizeof(list)))
602 return -EFAULT; 710 return -EFAULT;
603 offset = list.offset; 711 offset = list.offset;
604 space = list.space; 712 space = list.space;
605 first = 0;
606 /* try limit maximum space */ 713 /* try limit maximum space */
607 if (space > 16384) 714 if (space > 16384)
608 return -ENOMEM; 715 return -ENOMEM;
@@ -1488,7 +1595,7 @@ int snd_ctl_create(struct snd_card *card)
1488} 1595}
1489 1596
1490/* 1597/*
1491 * Frequently used control callbacks 1598 * Frequently used control callbacks/helpers
1492 */ 1599 */
1493int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol, 1600int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
1494 struct snd_ctl_elem_info *uinfo) 1601 struct snd_ctl_elem_info *uinfo)
@@ -1513,3 +1620,29 @@ int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
1513} 1620}
1514 1621
1515EXPORT_SYMBOL(snd_ctl_boolean_stereo_info); 1622EXPORT_SYMBOL(snd_ctl_boolean_stereo_info);
1623
1624/**
1625 * snd_ctl_enum_info - fills the info structure for an enumerated control
1626 * @info: the structure to be filled
1627 * @channels: the number of the control's channels; often one
1628 * @items: the number of control values; also the size of @names
1629 * @names: an array containing the names of all control values
1630 *
1631 * Sets all required fields in @info to their appropriate values.
1632 * If the control's accessibility is not the default (readable and writable),
1633 * the caller has to fill @info->access.
1634 */
1635int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
1636 unsigned int items, const char *const names[])
1637{
1638 info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1639 info->count = channels;
1640 info->value.enumerated.items = items;
1641 if (info->value.enumerated.item >= items)
1642 info->value.enumerated.item = items - 1;
1643 strlcpy(info->value.enumerated.name,
1644 names[info->value.enumerated.item],
1645 sizeof(info->value.enumerated.name));
1646 return 0;
1647}
1648EXPORT_SYMBOL(snd_ctl_enum_info);