diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /sound/core/control.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (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.c | 163 |
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 | ||
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 | } |
@@ -368,6 +366,70 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) | |||
368 | EXPORT_SYMBOL(snd_ctl_add); | 366 | EXPORT_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 | */ | ||
382 | int 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 | } | ||
411 | add: | ||
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 | |||
426 | error: | ||
427 | snd_ctl_free_one(kcontrol); | ||
428 | return ret; | ||
429 | } | ||
430 | EXPORT_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 | */ | ||
541 | int 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 | } | ||
574 | EXPORT_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 | */ |
1493 | int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol, | 1600 | int 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 | ||
1515 | EXPORT_SYMBOL(snd_ctl_boolean_stereo_info); | 1622 | EXPORT_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 | */ | ||
1635 | int 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 | } | ||
1648 | EXPORT_SYMBOL(snd_ctl_enum_info); | ||