[alsa-devel] [PATCH v4 1/6] ASoC: core: add snd_soc_add_dai_pcm_controls helper
Arnaud Pouliquen
arnaud.pouliquen at st.com
Tue Mar 8 13:53:56 CET 2016
Add helper function to register DAI controls that need to be
linked to pcm device.
A list is handled in case controls are created before dai_link probe
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen at st.com>
---
include/sound/soc-dai.h | 1 +
include/sound/soc.h | 2 +
sound/soc/soc-core.c | 164 +++++++++++++++++++++++++++++++++++++++++-------
3 files changed, 146 insertions(+), 21 deletions(-)
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 964b7de..6e0fcb0 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -292,6 +292,7 @@ struct snd_soc_dai {
unsigned int rx_mask;
struct list_head list;
+ struct list_head list_pcm_ctl;
};
static inline void *snd_soc_dai_get_dma_data(const struct snd_soc_dai *dai,
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 02b4a21..044adcf 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -598,6 +598,8 @@ int snd_soc_add_card_controls(struct snd_soc_card *soc_card,
const struct snd_kcontrol_new *controls, int num_controls);
int snd_soc_add_dai_controls(struct snd_soc_dai *dai,
const struct snd_kcontrol_new *controls, int num_controls);
+int snd_soc_add_dai_pcm_controls(struct snd_soc_dai *dai,
+ const struct snd_kcontrol_new *controls, int num_controls);
int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 790ee2b..95aae5e 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1582,11 +1582,63 @@ static int soc_link_dai_widgets(struct snd_soc_card *card,
return 0;
}
+static int snd_soc_add_controls(struct snd_card *card, struct device *dev,
+ const struct snd_kcontrol_new *controls, int num_controls,
+ const char *prefix, void *data)
+{
+ int err, i;
+
+ for (i = 0; i < num_controls; i++) {
+ const struct snd_kcontrol_new *control = &controls[i];
+
+ err = snd_ctl_add(card, snd_soc_cnew(control, data,
+ control->name, prefix));
+ if (err < 0) {
+ dev_err(dev, "ASoC: Failed to add %s: %d\n",
+ control->name, err);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+struct snd_soc_dai_pcm_ctls {
+ struct snd_kcontrol_new *controls;
+ int num_controls;
+ struct list_head list;
+};
+
+static int soc_link_dai_pcm_controls(struct snd_soc_card *card,
+ struct snd_soc_dai *dai,
+ struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai_pcm_ctls *ctls, *_ctls;
+ struct snd_kcontrol_new *kctl;
+ int i, ret;
+
+ list_for_each_entry_safe(ctls, _ctls, &dai->list_pcm_ctl, list) {
+ kctl = ctls->controls;
+ for (i = 0; i < ctls->num_controls; i++)
+ kctl[i].device = rtd->pcm->device;
+
+ ret = snd_soc_add_controls(card->snd_card, dai->dev, kctl,
+ ctls->num_controls, NULL, dai);
+ kfree(kctl);
+ list_del(&ctls->list);
+ kfree(ctls);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
static int soc_probe_link_dais(struct snd_soc_card *card,
struct snd_soc_pcm_runtime *rtd, int order)
{
struct snd_soc_dai_link *dai_link = rtd->dai_link;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *dai, *cpu_dai = rtd->cpu_dai;
int i, ret;
dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n",
@@ -1651,6 +1703,35 @@ static int soc_probe_link_dais(struct snd_soc_card *card,
dai_link->stream_name, ret);
return ret;
}
+
+ /* link CPU DAI pcm controls to pcm device */
+ if (!list_empty(&cpu_dai->list_pcm_ctl))
+ ret = soc_link_dai_pcm_controls(card, cpu_dai,
+ rtd);
+ if (ret < 0) {
+ dev_err(card->dev,
+ "ASoC: Can't link %s control to %s :%d\n",
+ cpu_dai->name, dai_link->stream_name,
+ ret);
+ return ret;
+ }
+
+ /* link CODEC DAI pcm control to pcm device */
+ for (i = 0; i < rtd->num_codecs; i++) {
+ dai = rtd->codec_dais[i];
+ if (!list_empty(&dai->list_pcm_ctl))
+ ret = soc_link_dai_pcm_controls(card,
+ dai, rtd);
+ if (ret < 0)
+ break;
+ }
+ if (ret < 0) {
+ dev_err(card->dev,
+ "ASoC: Can't link %s control to %s :%d\n",
+ dai->name, dai_link->stream_name, ret);
+ return ret;
+ }
+
} else {
INIT_DELAYED_WORK(&rtd->delayed_work,
codec2codec_close_delayed_work);
@@ -2187,26 +2268,6 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
}
EXPORT_SYMBOL_GPL(snd_soc_cnew);
-static int snd_soc_add_controls(struct snd_card *card, struct device *dev,
- const struct snd_kcontrol_new *controls, int num_controls,
- const char *prefix, void *data)
-{
- int err, i;
-
- for (i = 0; i < num_controls; i++) {
- const struct snd_kcontrol_new *control = &controls[i];
- err = snd_ctl_add(card, snd_soc_cnew(control, data,
- control->name, prefix));
- if (err < 0) {
- dev_err(dev, "ASoC: Failed to add %s: %d\n",
- control->name, err);
- return err;
- }
- }
-
- return 0;
-}
-
struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
const char *name)
{
@@ -2320,6 +2381,65 @@ int snd_soc_add_dai_controls(struct snd_soc_dai *dai,
EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls);
/**
+ * snd_soc_add_dai_pcm_controls - add an array of pcm controls to a DAI.
+ * Convenience function to add a list of DAI controls linked to the PCM device.
+ *
+ * @dai: DAI to add controls to
+ * @controls: array of controls to add
+ * @num_controls: number of elements in the array
+ *
+ * Return 0 for success, else error.
+ */
+int snd_soc_add_dai_pcm_controls(struct snd_soc_dai *dai,
+ const struct snd_kcontrol_new *controls,
+ int num_controls)
+{
+ struct snd_soc_card *card = dai->component->card;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_dai_pcm_ctls *ctls_list;
+ struct snd_kcontrol_new *kctl;
+ int i, dai_found = 0;
+
+ for (i = 0; i < num_controls; i++) {
+ if (controls[i].iface != SNDRV_CTL_ELEM_IFACE_PCM) {
+ dev_err(dai->dev, "%s: not a pcm device control !!!\n",
+ controls[i].name);
+ return -EINVAL;
+ }
+ }
+
+ kctl = kcalloc(num_controls, sizeof(*kctl), GFP_KERNEL);
+ memcpy(kctl, controls, sizeof(*kctl) * num_controls);
+
+ if (dai->probed) {
+ /* pcm device exists. Control can be linked to it */
+ list_for_each_entry(rtd, &card->rtd_list, list) {
+ if (dai == rtd->cpu_dai) {
+ dai_found = 1;
+ break;
+ }
+ }
+ if (!dai_found)
+ return -EINVAL;
+
+ for (i = 0; i < num_controls; i++)
+ kctl[i].device = rtd->pcm->device;
+ snd_soc_add_controls(card->snd_card, dai->dev, kctl,
+ num_controls, NULL, dai);
+ kfree(kctl);
+ } else {
+ /* pcm device does not exists. Postpone to dai link creation */
+ ctls_list = kzalloc(sizeof(*ctls_list), GFP_KERNEL);
+ ctls_list->controls = kctl;
+ ctls_list->num_controls = num_controls;
+ list_add(&ctls_list->list, &dai->list_pcm_ctl);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_add_dai_pcm_controls);
+
+/**
* snd_soc_dai_set_sysclk - configure DAI system or master clock.
* @dai: DAI
* @clk_id: DAI specific clock ID
@@ -2795,6 +2915,8 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component,
if (!dai->driver->ops)
dai->driver->ops = &null_dai_ops;
+ INIT_LIST_HEAD(&dai->list_pcm_ctl);
+
list_add(&dai->list, &component->dai_list);
component->num_dai++;
--
1.9.1
More information about the Alsa-devel
mailing list