aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/soc-dapm.c270
1 files changed, 136 insertions, 134 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 1d6a9b3ceb27..687784463db9 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -504,17 +504,27 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
504 return 0; 504 return 0;
505} 505}
506 506
507/* create new dapm mixer control */ 507/*
508static int dapm_new_mixer(struct snd_soc_dapm_widget *w) 508 * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
509 * create it. Either way, add the widget into the control's widget list
510 */
511static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
512 int kci, struct snd_soc_dapm_path *path)
509{ 513{
510 struct snd_soc_dapm_context *dapm = w->dapm; 514 struct snd_soc_dapm_context *dapm = w->dapm;
511 int i, ret = 0;
512 size_t name_len, prefix_len;
513 struct snd_soc_dapm_path *path;
514 struct snd_card *card = dapm->card->snd_card; 515 struct snd_card *card = dapm->card->snd_card;
515 const char *prefix; 516 const char *prefix;
517 size_t prefix_len;
518 int shared;
519 struct snd_kcontrol *kcontrol;
516 struct snd_soc_dapm_widget_list *wlist; 520 struct snd_soc_dapm_widget_list *wlist;
521 int wlistentries;
517 size_t wlistsize; 522 size_t wlistsize;
523 bool wname_in_long_name, kcname_in_long_name;
524 size_t name_len;
525 char *long_name;
526 const char *name;
527 int ret;
518 528
519 if (dapm->codec) 529 if (dapm->codec)
520 prefix = dapm->codec->name_prefix; 530 prefix = dapm->codec->name_prefix;
@@ -526,103 +536,141 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
526 else 536 else
527 prefix_len = 0; 537 prefix_len = 0;
528 538
529 /* add kcontrol */ 539 shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
530 for (i = 0; i < w->num_kcontrols; i++) { 540 &kcontrol);
531 541
532 /* match name */ 542 if (kcontrol) {
533 list_for_each_entry(path, &w->sources, list_sink) { 543 wlist = kcontrol->private_data;
544 wlistentries = wlist->num_widgets + 1;
545 } else {
546 wlist = NULL;
547 wlistentries = 1;
548 }
534 549
535 /* mixer/mux paths name must match control name */ 550 wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
536 if (path->name != (char *)w->kcontrol_news[i].name) 551 wlistentries * sizeof(struct snd_soc_dapm_widget *);
537 continue; 552 wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
553 if (wlist == NULL) {
554 dev_err(dapm->dev, "ASoC: can't allocate widget list for %s\n",
555 w->name);
556 return -ENOMEM;
557 }
558 wlist->num_widgets = wlistentries;
559 wlist->widgets[wlistentries - 1] = w;
538 560
539 if (w->kcontrols[i]) { 561 if (!kcontrol) {
540 path->kcontrol = w->kcontrols[i]; 562 if (shared) {
541 continue; 563 wname_in_long_name = false;
564 kcname_in_long_name = true;
565 } else {
566 switch (w->id) {
567 case snd_soc_dapm_switch:
568 case snd_soc_dapm_mixer:
569 wname_in_long_name = true;
570 kcname_in_long_name = true;
571 break;
572 case snd_soc_dapm_mixer_named_ctl:
573 wname_in_long_name = false;
574 kcname_in_long_name = true;
575 break;
576 case snd_soc_dapm_mux:
577 case snd_soc_dapm_virt_mux:
578 case snd_soc_dapm_value_mux:
579 wname_in_long_name = true;
580 kcname_in_long_name = false;
581 break;
582 default:
583 kfree(wlist);
584 return -EINVAL;
542 } 585 }
586 }
587
588 if (wname_in_long_name && kcname_in_long_name) {
589 name_len = strlen(w->name) - prefix_len + 1 +
590 strlen(w->kcontrol_news[kci].name) + 1;
543 591
544 wlistsize = sizeof(struct snd_soc_dapm_widget_list) + 592 long_name = kmalloc(name_len, GFP_KERNEL);
545 sizeof(struct snd_soc_dapm_widget *), 593 if (long_name == NULL) {
546 wlist = kzalloc(wlistsize, GFP_KERNEL); 594 kfree(wlist);
547 if (wlist == NULL) {
548 dev_err(dapm->dev,
549 "ASoC: can't allocate widget list for %s\n",
550 w->name);
551 return -ENOMEM; 595 return -ENOMEM;
552 } 596 }
553 wlist->num_widgets = 1; 597
554 wlist->widgets[0] = w; 598 /*
555 599 * The control will get a prefix from the control
556 /* add dapm control with long name. 600 * creation process but we're also using the same
557 * for dapm_mixer this is the concatenation of the 601 * prefix for widgets so cut the prefix off the
558 * mixer and kcontrol name. 602 * front of the widget name.
559 * for dapm_mixer_named_ctl this is simply the
560 * kcontrol name.
561 */ 603 */
562 name_len = strlen(w->kcontrol_news[i].name) + 1; 604 snprintf(long_name, name_len, "%s %s",
563 if (w->id != snd_soc_dapm_mixer_named_ctl) 605 w->name + prefix_len,
564 name_len += 1 + strlen(w->name); 606 w->kcontrol_news[kci].name);
607 long_name[name_len - 1] = '\0';
608
609 name = long_name;
610 } else if (wname_in_long_name) {
611 long_name = NULL;
612 name = w->name + prefix_len;
613 } else {
614 long_name = NULL;
615 name = w->kcontrol_news[kci].name;
616 }
565 617
566 path->long_name = kmalloc(name_len, GFP_KERNEL); 618 kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name,
619 prefix);
620 ret = snd_ctl_add(card, kcontrol);
621 if (ret < 0) {
622 dev_err(dapm->dev,
623 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
624 w->name, name, ret);
625 kfree(wlist);
626 kfree(long_name);
627 return ret;
628 }
567 629
568 if (path->long_name == NULL) { 630 path->long_name = long_name;
569 kfree(wlist); 631 }
570 return -ENOMEM;
571 }
572 632
573 switch (w->id) { 633 kcontrol->private_data = wlist;
574 default: 634 w->kcontrols[kci] = kcontrol;
575 /* The control will get a prefix from 635 path->kcontrol = kcontrol;
576 * the control creation process but
577 * we're also using the same prefix
578 * for widgets so cut the prefix off
579 * the front of the widget name.
580 */
581 snprintf((char *)path->long_name, name_len,
582 "%s %s", w->name + prefix_len,
583 w->kcontrol_news[i].name);
584 break;
585 case snd_soc_dapm_mixer_named_ctl:
586 snprintf((char *)path->long_name, name_len,
587 "%s", w->kcontrol_news[i].name);
588 break;
589 }
590 636
591 ((char *)path->long_name)[name_len - 1] = '\0'; 637 return 0;
638}
592 639
593 path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i], 640/* create new dapm mixer control */
594 wlist, path->long_name, 641static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
595 prefix); 642{
596 ret = snd_ctl_add(card, path->kcontrol); 643 int i, ret;
597 if (ret < 0) { 644 struct snd_soc_dapm_path *path;
598 dev_err(dapm->dev, "ASoC: failed to add widget" 645
599 " %s dapm kcontrol %s: %d\n", 646 /* add kcontrol */
600 w->name, path->long_name, ret); 647 for (i = 0; i < w->num_kcontrols; i++) {
601 kfree(wlist); 648 /* match name */
602 kfree(path->long_name); 649 list_for_each_entry(path, &w->sources, list_sink) {
603 path->long_name = NULL; 650 /* mixer/mux paths name must match control name */
604 return ret; 651 if (path->name != (char *)w->kcontrol_news[i].name)
652 continue;
653
654 if (w->kcontrols[i]) {
655 path->kcontrol = w->kcontrols[i];
656 continue;
605 } 657 }
606 w->kcontrols[i] = path->kcontrol; 658
659 ret = dapm_create_or_share_mixmux_kcontrol(w, i, path);
660 if (ret < 0)
661 return ret;
607 } 662 }
608 } 663 }
609 return ret; 664
665 return 0;
610} 666}
611 667
612/* create new dapm mux control */ 668/* create new dapm mux control */
613static int dapm_new_mux(struct snd_soc_dapm_widget *w) 669static int dapm_new_mux(struct snd_soc_dapm_widget *w)
614{ 670{
615 struct snd_soc_dapm_context *dapm = w->dapm; 671 struct snd_soc_dapm_context *dapm = w->dapm;
616 struct snd_soc_dapm_path *path = NULL; 672 struct snd_soc_dapm_path *path;
617 struct snd_kcontrol *kcontrol;
618 struct snd_card *card = dapm->card->snd_card;
619 const char *prefix;
620 size_t prefix_len;
621 int ret; 673 int ret;
622 struct snd_soc_dapm_widget_list *wlist;
623 int shared, wlistentries;
624 size_t wlistsize;
625 const char *name;
626 674
627 if (w->num_kcontrols != 1) { 675 if (w->num_kcontrols != 1) {
628 dev_err(dapm->dev, 676 dev_err(dapm->dev,
@@ -631,65 +679,19 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
631 return -EINVAL; 679 return -EINVAL;
632 } 680 }
633 681
634 shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[0], 682 path = list_first_entry(&w->sources, struct snd_soc_dapm_path,
635 &kcontrol); 683 list_sink);
636 if (kcontrol) { 684 if (!path) {
637 wlist = kcontrol->private_data; 685 dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name);
638 wlistentries = wlist->num_widgets + 1; 686 return -EINVAL;
639 } else {
640 wlist = NULL;
641 wlistentries = 1;
642 }
643 wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
644 wlistentries * sizeof(struct snd_soc_dapm_widget *),
645 wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
646 if (wlist == NULL) {
647 dev_err(dapm->dev,
648 "ASoC: can't allocate widget list for %s\n", w->name);
649 return -ENOMEM;
650 }
651 wlist->num_widgets = wlistentries;
652 wlist->widgets[wlistentries - 1] = w;
653
654 if (!kcontrol) {
655 if (dapm->codec)
656 prefix = dapm->codec->name_prefix;
657 else
658 prefix = NULL;
659
660 if (shared) {
661 name = w->kcontrol_news[0].name;
662 prefix_len = 0;
663 } else {
664 name = w->name;
665 if (prefix)
666 prefix_len = strlen(prefix) + 1;
667 else
668 prefix_len = 0;
669 }
670
671 /*
672 * The control will get a prefix from the control creation
673 * process but we're also using the same prefix for widgets so
674 * cut the prefix off the front of the widget name.
675 */
676 kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist,
677 name + prefix_len, prefix);
678 ret = snd_ctl_add(card, kcontrol);
679 if (ret < 0) {
680 dev_err(dapm->dev, "ASoC: failed to add kcontrol %s: %d\n",
681 w->name, ret);
682 kfree(wlist);
683 return ret;
684 }
685 } 687 }
686 688
687 kcontrol->private_data = wlist; 689 ret = dapm_create_or_share_mixmux_kcontrol(w, 0, path);
688 690 if (ret < 0)
689 w->kcontrols[0] = kcontrol; 691 return ret;
690 692
691 list_for_each_entry(path, &w->sources, list_sink) 693 list_for_each_entry(path, &w->sources, list_sink)
692 path->kcontrol = kcontrol; 694 path->kcontrol = w->kcontrols[0];
693 695
694 return 0; 696 return 0;
695} 697}