diff options
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 110 |
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 | ||
510 | static 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 | ||
2110 | static 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 */ |
2098 | static void dapm_free_widgets(struct snd_soc_dapm_context *dapm) | 2119 | static 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: |