0001
0002
0003
0004
0005
0006 #include <linux/debugfs.h>
0007 #include <sound/core.h>
0008 #include <sound/soc.h>
0009 #include <sound/soc-dapm.h>
0010 #include "audio_helper.h"
0011
0012 #define gbaudio_dapm_for_each_direction(dir) \
0013 for ((dir) = SND_SOC_DAPM_DIR_IN; (dir) <= SND_SOC_DAPM_DIR_OUT; \
0014 (dir)++)
0015
0016 static void gbaudio_dapm_link_dai_widget(struct snd_soc_dapm_widget *dai_w,
0017 struct snd_soc_card *card)
0018 {
0019 struct snd_soc_dapm_widget *w;
0020 struct snd_soc_dapm_widget *src, *sink;
0021 struct snd_soc_dai *dai = dai_w->priv;
0022
0023
0024 list_for_each_entry(w, &card->widgets, list) {
0025 if (w->dapm != dai_w->dapm)
0026 continue;
0027
0028 switch (w->id) {
0029 case snd_soc_dapm_dai_in:
0030 case snd_soc_dapm_dai_out:
0031 continue;
0032 default:
0033 break;
0034 }
0035
0036 if (!w->sname || !strstr(w->sname, dai_w->sname))
0037 continue;
0038
0039
0040
0041
0042
0043
0044
0045 if (dai_w->id == snd_soc_dapm_dai_in) {
0046 src = dai_w;
0047 sink = w;
0048 } else {
0049 src = w;
0050 sink = dai_w;
0051 }
0052 dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name);
0053
0054
0055
0056
0057 }
0058 }
0059
0060 int gbaudio_dapm_link_component_dai_widgets(struct snd_soc_card *card,
0061 struct snd_soc_dapm_context *dapm)
0062 {
0063 struct snd_soc_dapm_widget *dai_w;
0064
0065
0066 list_for_each_entry(dai_w, &card->widgets, list) {
0067 if (dai_w->dapm != dapm)
0068 continue;
0069 switch (dai_w->id) {
0070 case snd_soc_dapm_dai_in:
0071 case snd_soc_dapm_dai_out:
0072 break;
0073 default:
0074 continue;
0075 }
0076 gbaudio_dapm_link_dai_widget(dai_w, card);
0077 }
0078
0079 return 0;
0080 }
0081
0082 static void gbaudio_dapm_free_path(struct snd_soc_dapm_path *path)
0083 {
0084 list_del(&path->list_node[SND_SOC_DAPM_DIR_IN]);
0085 list_del(&path->list_node[SND_SOC_DAPM_DIR_OUT]);
0086 list_del(&path->list_kcontrol);
0087 list_del(&path->list);
0088 kfree(path);
0089 }
0090
0091 static void gbaudio_dapm_free_widget(struct snd_soc_dapm_widget *w)
0092 {
0093 struct snd_soc_dapm_path *p, *next_p;
0094 enum snd_soc_dapm_direction dir;
0095
0096 list_del(&w->list);
0097
0098
0099
0100
0101
0102 gbaudio_dapm_for_each_direction(dir) {
0103 snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p)
0104 gbaudio_dapm_free_path(p);
0105 }
0106
0107 kfree(w->kcontrols);
0108 kfree_const(w->name);
0109 kfree_const(w->sname);
0110 kfree(w);
0111 }
0112
0113 int gbaudio_dapm_free_controls(struct snd_soc_dapm_context *dapm,
0114 const struct snd_soc_dapm_widget *widget,
0115 int num)
0116 {
0117 int i;
0118 struct snd_soc_dapm_widget *w, *tmp_w;
0119 #ifdef CONFIG_DEBUG_FS
0120 struct dentry *parent = dapm->debugfs_dapm;
0121 struct dentry *debugfs_w = NULL;
0122 #endif
0123
0124 mutex_lock(&dapm->card->dapm_mutex);
0125 for (i = 0; i < num; i++) {
0126
0127 w = NULL;
0128 list_for_each_entry(tmp_w, &dapm->card->widgets, list) {
0129 if (tmp_w->dapm == dapm &&
0130 !strcmp(tmp_w->name, widget->name)) {
0131 w = tmp_w;
0132 break;
0133 }
0134 }
0135 if (!w) {
0136 dev_err(dapm->dev, "%s: widget not found\n",
0137 widget->name);
0138 widget++;
0139 continue;
0140 }
0141 widget++;
0142 #ifdef CONFIG_DEBUG_FS
0143 if (!parent)
0144 debugfs_w = debugfs_lookup(w->name, parent);
0145 debugfs_remove(debugfs_w);
0146 debugfs_w = NULL;
0147 #endif
0148 gbaudio_dapm_free_widget(w);
0149 }
0150 mutex_unlock(&dapm->card->dapm_mutex);
0151 return 0;
0152 }
0153
0154 static int gbaudio_remove_controls(struct snd_card *card, struct device *dev,
0155 const struct snd_kcontrol_new *controls,
0156 int num_controls, const char *prefix)
0157 {
0158 int i, err;
0159
0160 for (i = 0; i < num_controls; i++) {
0161 const struct snd_kcontrol_new *control = &controls[i];
0162 struct snd_ctl_elem_id id;
0163 struct snd_kcontrol *kctl;
0164
0165 if (prefix)
0166 snprintf(id.name, sizeof(id.name), "%s %s", prefix,
0167 control->name);
0168 else
0169 strscpy(id.name, control->name, sizeof(id.name));
0170 id.numid = 0;
0171 id.iface = control->iface;
0172 id.device = control->device;
0173 id.subdevice = control->subdevice;
0174 id.index = control->index;
0175 kctl = snd_ctl_find_id(card, &id);
0176 if (!kctl) {
0177 dev_err(dev, "Failed to find %s\n", control->name);
0178 continue;
0179 }
0180 err = snd_ctl_remove(card, kctl);
0181 if (err < 0) {
0182 dev_err(dev, "%d: Failed to remove %s\n", err,
0183 control->name);
0184 continue;
0185 }
0186 }
0187 return 0;
0188 }
0189
0190 int gbaudio_remove_component_controls(struct snd_soc_component *component,
0191 const struct snd_kcontrol_new *controls,
0192 unsigned int num_controls)
0193 {
0194 struct snd_card *card = component->card->snd_card;
0195 int err;
0196
0197 down_write(&card->controls_rwsem);
0198 err = gbaudio_remove_controls(card, component->dev, controls,
0199 num_controls, component->name_prefix);
0200 up_write(&card->controls_rwsem);
0201 return err;
0202 }