aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-dapm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r--sound/soc/soc-dapm.c110
1 files changed, 58 insertions, 52 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index c7051c457b75..b94190820e8c 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -64,6 +64,7 @@ static int dapm_up_seq[] = {
64 [snd_soc_dapm_virt_mux] = 5, 64 [snd_soc_dapm_virt_mux] = 5,
65 [snd_soc_dapm_value_mux] = 5, 65 [snd_soc_dapm_value_mux] = 5,
66 [snd_soc_dapm_dac] = 6, 66 [snd_soc_dapm_dac] = 6,
67 [snd_soc_dapm_switch] = 7,
67 [snd_soc_dapm_mixer] = 7, 68 [snd_soc_dapm_mixer] = 7,
68 [snd_soc_dapm_mixer_named_ctl] = 7, 69 [snd_soc_dapm_mixer_named_ctl] = 7,
69 [snd_soc_dapm_pga] = 8, 70 [snd_soc_dapm_pga] = 8,
@@ -83,6 +84,7 @@ static int dapm_down_seq[] = {
83 [snd_soc_dapm_line] = 2, 84 [snd_soc_dapm_line] = 2,
84 [snd_soc_dapm_out_drv] = 2, 85 [snd_soc_dapm_out_drv] = 2,
85 [snd_soc_dapm_pga] = 4, 86 [snd_soc_dapm_pga] = 4,
87 [snd_soc_dapm_switch] = 5,
86 [snd_soc_dapm_mixer_named_ctl] = 5, 88 [snd_soc_dapm_mixer_named_ctl] = 5,
87 [snd_soc_dapm_mixer] = 5, 89 [snd_soc_dapm_mixer] = 5,
88 [snd_soc_dapm_dac] = 6, 90 [snd_soc_dapm_dac] = 6,
@@ -365,11 +367,10 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
365 val = soc_widget_read(w, e->reg); 367 val = soc_widget_read(w, e->reg);
366 item = (val >> e->shift_l) & e->mask; 368 item = (val >> e->shift_l) & e->mask;
367 369
368 p->connect = 0; 370 if (item < e->max && !strcmp(p->name, e->texts[item]))
369 for (i = 0; i < e->max; i++) { 371 p->connect = 1;
370 if (!(strcmp(p->name, e->texts[i])) && item == i) 372 else
371 p->connect = 1; 373 p->connect = 0;
372 }
373 } 374 }
374 break; 375 break;
375 case snd_soc_dapm_virt_mux: { 376 case snd_soc_dapm_virt_mux: {
@@ -399,11 +400,10 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
399 break; 400 break;
400 } 401 }
401 402
402 p->connect = 0; 403 if (item < e->max && !strcmp(p->name, e->texts[item]))
403 for (i = 0; i < e->max; i++) { 404 p->connect = 1;
404 if (!(strcmp(p->name, e->texts[i])) && item == i) 405 else
405 p->connect = 1; 406 p->connect = 0;
406 }
407 } 407 }
408 break; 408 break;
409 /* does not affect routing - always connected */ 409 /* does not affect routing - always connected */
@@ -507,6 +507,11 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
507 return 0; 507 return 0;
508} 508}
509 509
510static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
511{
512 kfree(kctl->private_data);
513}
514
510/* 515/*
511 * Determine if a kcontrol is shared. If it is, look it up. If it isn't, 516 * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
512 * create it. Either way, add the widget into the control's widget list 517 * create it. Either way, add the widget into the control's widget list
@@ -524,7 +529,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
524 int wlistentries; 529 int wlistentries;
525 size_t wlistsize; 530 size_t wlistsize;
526 bool wname_in_long_name, kcname_in_long_name; 531 bool wname_in_long_name, kcname_in_long_name;
527 size_t name_len;
528 char *long_name; 532 char *long_name;
529 const char *name; 533 const char *name;
530 int ret; 534 int ret;
@@ -589,25 +593,19 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
589 } 593 }
590 594
591 if (wname_in_long_name && kcname_in_long_name) { 595 if (wname_in_long_name && kcname_in_long_name) {
592 name_len = strlen(w->name) - prefix_len + 1 +
593 strlen(w->kcontrol_news[kci].name) + 1;
594
595 long_name = kmalloc(name_len, GFP_KERNEL);
596 if (long_name == NULL) {
597 kfree(wlist);
598 return -ENOMEM;
599 }
600
601 /* 596 /*
602 * The control will get a prefix from the control 597 * The control will get a prefix from the control
603 * creation process but we're also using the same 598 * creation process but we're also using the same
604 * prefix for widgets so cut the prefix off the 599 * prefix for widgets so cut the prefix off the
605 * front of the widget name. 600 * front of the widget name.
606 */ 601 */
607 snprintf(long_name, name_len, "%s %s", 602 long_name = kasprintf(GFP_KERNEL, "%s %s",
608 w->name + prefix_len, 603 w->name + prefix_len,
609 w->kcontrol_news[kci].name); 604 w->kcontrol_news[kci].name);
610 long_name[name_len - 1] = '\0'; 605 if (long_name == NULL) {
606 kfree(wlist);
607 return -ENOMEM;
608 }
611 609
612 name = long_name; 610 name = long_name;
613 } else if (wname_in_long_name) { 611 } else if (wname_in_long_name) {
@@ -620,17 +618,16 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
620 618
621 kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name, 619 kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name,
622 prefix); 620 prefix);
621 kcontrol->private_free = dapm_kcontrol_free;
622 kfree(long_name);
623 ret = snd_ctl_add(card, kcontrol); 623 ret = snd_ctl_add(card, kcontrol);
624 if (ret < 0) { 624 if (ret < 0) {
625 dev_err(dapm->dev, 625 dev_err(dapm->dev,
626 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n", 626 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
627 w->name, name, ret); 627 w->name, name, ret);
628 kfree(wlist); 628 kfree(wlist);
629 kfree(long_name);
630 return ret; 629 return ret;
631 } 630 }
632
633 path->long_name = long_name;
634 } 631 }
635 632
636 kcontrol->private_data = wlist; 633 kcontrol->private_data = wlist;
@@ -1270,6 +1267,14 @@ static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
1270 ev_name = "POST_PMD"; 1267 ev_name = "POST_PMD";
1271 power = 0; 1268 power = 0;
1272 break; 1269 break;
1270 case SND_SOC_DAPM_WILL_PMU:
1271 ev_name = "WILL_PMU";
1272 power = 1;
1273 break;
1274 case SND_SOC_DAPM_WILL_PMD:
1275 ev_name = "WILL_PMD";
1276 power = 0;
1277 break;
1273 default: 1278 default:
1274 BUG(); 1279 BUG();
1275 return; 1280 return;
@@ -1730,6 +1735,14 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
1730 &async_domain); 1735 &async_domain);
1731 async_synchronize_full_domain(&async_domain); 1736 async_synchronize_full_domain(&async_domain);
1732 1737
1738 list_for_each_entry(w, &down_list, power_list) {
1739 dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMD);
1740 }
1741
1742 list_for_each_entry(w, &up_list, power_list) {
1743 dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMU);
1744 }
1745
1733 /* Power down widgets first; try to avoid amplifying pops. */ 1746 /* Power down widgets first; try to avoid amplifying pops. */
1734 dapm_seq_run(dapm, &down_list, event, false); 1747 dapm_seq_run(dapm, &down_list, event, false);
1735 1748
@@ -2094,6 +2107,14 @@ static void snd_soc_dapm_sys_remove(struct device *dev)
2094 device_remove_file(dev, &dev_attr_dapm_widget); 2107 device_remove_file(dev, &dev_attr_dapm_widget);
2095} 2108}
2096 2109
2110static void dapm_free_path(struct snd_soc_dapm_path *path)
2111{
2112 list_del(&path->list_sink);
2113 list_del(&path->list_source);
2114 list_del(&path->list);
2115 kfree(path);
2116}
2117
2097/* free all dapm widgets and resources */ 2118/* free all dapm widgets and resources */
2098static void dapm_free_widgets(struct snd_soc_dapm_context *dapm) 2119static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
2099{ 2120{
@@ -2109,20 +2130,12 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
2109 * While removing the path, remove reference to it from both 2130 * While removing the path, remove reference to it from both
2110 * source and sink widgets so that path is removed only once. 2131 * source and sink widgets so that path is removed only once.
2111 */ 2132 */
2112 list_for_each_entry_safe(p, next_p, &w->sources, list_sink) { 2133 list_for_each_entry_safe(p, next_p, &w->sources, list_sink)
2113 list_del(&p->list_sink); 2134 dapm_free_path(p);
2114 list_del(&p->list_source); 2135
2115 list_del(&p->list); 2136 list_for_each_entry_safe(p, next_p, &w->sinks, list_source)
2116 kfree(p->long_name); 2137 dapm_free_path(p);
2117 kfree(p); 2138
2118 }
2119 list_for_each_entry_safe(p, next_p, &w->sinks, list_source) {
2120 list_del(&p->list_sink);
2121 list_del(&p->list_source);
2122 list_del(&p->list);
2123 kfree(p->long_name);
2124 kfree(p);
2125 }
2126 kfree(w->kcontrols); 2139 kfree(w->kcontrols);
2127 kfree(w->name); 2140 kfree(w->name);
2128 kfree(w); 2141 kfree(w);
@@ -2398,10 +2411,7 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
2398 dapm_mark_dirty(path->source, "Route removed"); 2411 dapm_mark_dirty(path->source, "Route removed");
2399 dapm_mark_dirty(path->sink, "Route removed"); 2412 dapm_mark_dirty(path->sink, "Route removed");
2400 2413
2401 list_del(&path->list); 2414 dapm_free_path(path);
2402 list_del(&path->list_sink);
2403 list_del(&path->list_source);
2404 kfree(path);
2405 } else { 2415 } else {
2406 dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n", 2416 dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
2407 source, sink); 2417 source, sink);
@@ -3055,7 +3065,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
3055 const struct snd_soc_dapm_widget *widget) 3065 const struct snd_soc_dapm_widget *widget)
3056{ 3066{
3057 struct snd_soc_dapm_widget *w; 3067 struct snd_soc_dapm_widget *w;
3058 size_t name_len;
3059 int ret; 3068 int ret;
3060 3069
3061 if ((w = dapm_cnew_widget(widget)) == NULL) 3070 if ((w = dapm_cnew_widget(widget)) == NULL)
@@ -3096,19 +3105,16 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
3096 break; 3105 break;
3097 } 3106 }
3098 3107
3099 name_len = strlen(widget->name) + 1;
3100 if (dapm->codec && dapm->codec->name_prefix) 3108 if (dapm->codec && dapm->codec->name_prefix)
3101 name_len += 1 + strlen(dapm->codec->name_prefix); 3109 w->name = kasprintf(GFP_KERNEL, "%s %s",
3102 w->name = kmalloc(name_len, GFP_KERNEL); 3110 dapm->codec->name_prefix, widget->name);
3111 else
3112 w->name = kasprintf(GFP_KERNEL, "%s", widget->name);
3113
3103 if (w->name == NULL) { 3114 if (w->name == NULL) {
3104 kfree(w); 3115 kfree(w);
3105 return NULL; 3116 return NULL;
3106 } 3117 }
3107 if (dapm->codec && dapm->codec->name_prefix)
3108 snprintf((char *)w->name, name_len, "%s %s",
3109 dapm->codec->name_prefix, widget->name);
3110 else
3111 snprintf((char *)w->name, name_len, "%s", widget->name);
3112 3118
3113 switch (w->id) { 3119 switch (w->id) {
3114 case snd_soc_dapm_switch: 3120 case snd_soc_dapm_switch: