[alsa-devel] [PATCH 1/8] ALSA: core: Constify the name in new kcontrols
We never modify it and this lets us use a const string as the name without warnings.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- include/sound/control.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/include/sound/control.h b/include/sound/control.h index b2796e8..57815f6 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -40,7 +40,7 @@ struct snd_kcontrol_new { snd_ctl_elem_iface_t iface; /* interface identifier */ unsigned int device; /* device/client number */ unsigned int subdevice; /* subdevice (substream) number */ - unsigned char *name; /* ASCII name of item */ + const unsigned char *name; /* ASCII name of item */ unsigned int index; /* index of item */ unsigned int access; /* access rights */ unsigned int count; /* count of same elements */
Everything now uses snd_soc_dapm_new_controls() instead so we don't need to make it part of the external API.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- include/sound/soc-dapm.h | 2 -- sound/soc/soc-dapm.c | 5 ++--- 2 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index db8435a..c28d20b 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -352,8 +352,6 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uncontrol); int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uncontrol); -int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget); int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget, int num); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d3f6bad0..c7032fa 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2710,8 +2710,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); * * Returns 0 for success else error. */ -int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget) +static int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, + const struct snd_soc_dapm_widget *widget) { struct snd_soc_dapm_widget *w; size_t name_len; @@ -2801,7 +2801,6 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, w->connected = 1; return 0; } -EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
/** * snd_soc_dapm_new_controls - create new dapm controls
Let the caller fiddle with the widget after we're done in order to facilitate further refactoring.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/soc-dapm.c | 35 ++++++++++++++--------------------- 1 files changed, 14 insertions(+), 21 deletions(-)
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c7032fa..bfaa9d2 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2701,24 +2701,16 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
-/** - * snd_soc_dapm_new_control - create new dapm control - * @dapm: DAPM context - * @widget: widget template - * - * Creates a new dapm control based upon the template. - * - * Returns 0 for success else error. - */ -static int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget) +static struct snd_soc_dapm_widget * +snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, + const struct snd_soc_dapm_widget *widget) { struct snd_soc_dapm_widget *w; size_t name_len; int ret;
if ((w = dapm_cnew_widget(widget)) == NULL) - return -ENOMEM; + return NULL;
switch (w->id) { case snd_soc_dapm_regulator_supply: @@ -2727,7 +2719,7 @@ static int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, ret = PTR_ERR(w->priv); dev_err(dapm->dev, "Failed to request %s: %d\n", w->name, ret); - return ret; + return NULL; } break; default: @@ -2740,7 +2732,7 @@ static int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, w->name = kmalloc(name_len, GFP_KERNEL); if (w->name == NULL) { kfree(w); - return -ENOMEM; + return NULL; } if (dapm->codec && dapm->codec->name_prefix) snprintf(w->name, name_len, "%s %s", @@ -2799,7 +2791,7 @@ static int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
/* machine layer set ups unconnected pins and insertions */ w->connected = 1; - return 0; + return w; }
/** @@ -2816,15 +2808,16 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget, int num) { - int i, ret; + struct snd_soc_dapm_widget *w; + int i;
for (i = 0; i < num; i++) { - ret = snd_soc_dapm_new_control(dapm, widget); - if (ret < 0) { + w = snd_soc_dapm_new_control(dapm, widget); + if (!w) { dev_err(dapm->dev, - "ASoC: Failed to create DAPM control %s: %d\n", - widget->name, ret); - return ret; + "ASoC: Failed to create DAPM control %s\n", + widget->name); + return -ENOMEM; } widget++; }
In order to allow us to do something smarter than iterate through widgets doing strcmp() to work out what to power up for stream events change the interface used to generate them to be based on the combination of a DAI and a stream direction rather than just a simple string identifying the stream.
At some point we'll probably want a set of channels too.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- include/sound/soc-dapm.h | 4 ++-- sound/soc/soc-core.c | 30 ++++++++++++++++-------------- sound/soc/soc-dapm.c | 25 ++++++++++++++++--------- sound/soc/soc-pcm.c | 25 +++++++++---------------- 4 files changed, 43 insertions(+), 41 deletions(-)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index c28d20b..c32c521 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -365,8 +365,8 @@ int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_route *route, int num);
/* dapm events */ -int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, - const char *stream, int event); +int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, + struct snd_soc_dai *dai, int event); void snd_soc_dapm_shutdown(struct snd_soc_card *card);
/* external DAPM widget events */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 09b8fde..87a3c5c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -573,18 +573,20 @@ int snd_soc_suspend(struct device *dev) }
for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver; + struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
if (card->rtd[i].dai_link->ignore_suspend) continue;
- if (driver->playback.stream_name != NULL) - snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name, - SND_SOC_DAPM_STREAM_SUSPEND); + snd_soc_dapm_stream_event(&card->rtd[i], + SNDRV_PCM_STREAM_PLAYBACK, + codec_dai, + SND_SOC_DAPM_STREAM_SUSPEND);
- if (driver->capture.stream_name != NULL) - snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name, - SND_SOC_DAPM_STREAM_SUSPEND); + snd_soc_dapm_stream_event(&card->rtd[i], + SNDRV_PCM_STREAM_CAPTURE, + codec_dai, + SND_SOC_DAPM_STREAM_SUSPEND); }
/* suspend all CODECs */ @@ -687,18 +689,18 @@ static void soc_resume_deferred(struct work_struct *work) }
for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver; + struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
if (card->rtd[i].dai_link->ignore_suspend) continue;
- if (driver->playback.stream_name != NULL) - snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name, - SND_SOC_DAPM_STREAM_RESUME); + snd_soc_dapm_stream_event(&card->rtd[i], + SNDRV_PCM_STREAM_PLAYBACK, codec_dai, + SND_SOC_DAPM_STREAM_RESUME);
- if (driver->capture.stream_name != NULL) - snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name, - SND_SOC_DAPM_STREAM_RESUME); + snd_soc_dapm_stream_event(&card->rtd[i], + SNDRV_PCM_STREAM_CAPTURE, codec_dai, + SND_SOC_DAPM_STREAM_RESUME); }
/* unmute any active DACs */ diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index bfaa9d2..21c7b31 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2826,17 +2826,27 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, - const char *stream, int event) + int stream, struct snd_soc_dai *dai, + int event) { struct snd_soc_dapm_widget *w; + const char *stream_name; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + stream_name = dai->driver->playback.stream_name; + else + stream_name = dai->driver->capture.stream_name; + + if (!stream_name) + return;
list_for_each_entry(w, &dapm->card->widgets, list) { if (!w->sname || w->dapm != dapm) continue; dev_vdbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n", - w->name, w->sname, stream, event); - if (strstr(w->sname, stream)) { + w->name, w->sname, stream_name, event); + if (strstr(w->sname, stream_name)) { dapm_mark_dirty(w, "stream event"); switch(event) { case SND_SOC_DAPM_STREAM_START: @@ -2868,16 +2878,13 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, * * Returns 0 for success else error. */ -int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, - const char *stream, int event) +int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, + struct snd_soc_dai *dai, int event) { struct snd_soc_codec *codec = rtd->codec;
- if (stream == NULL) - return 0; - mutex_lock(&codec->mutex); - soc_dapm_stream_event(&codec->dapm, stream, event); + soc_dapm_stream_event(&codec->dapm, stream, dai, event); mutex_unlock(&codec->mutex); return 0; } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index d7bb268..2896904 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -307,9 +307,8 @@ static void close_delayed_work(struct work_struct *work) /* are we waiting on this codec DAI stream */ if (codec_dai->pop_wait == 1) { codec_dai->pop_wait = 0; - snd_soc_dapm_stream_event(rtd, - codec_dai->driver->playback.stream_name, - SND_SOC_DAPM_STREAM_STOP); + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, + codec_dai, SND_SOC_DAPM_STREAM_STOP); }
mutex_unlock(&rtd->pcm_mutex); @@ -373,8 +372,9 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) rtd->dai_link->ignore_pmdown_time) { /* powered down playback stream now */ snd_soc_dapm_stream_event(rtd, - codec_dai->driver->playback.stream_name, - SND_SOC_DAPM_STREAM_STOP); + SNDRV_PCM_STREAM_PLAYBACK, + codec_dai, + SND_SOC_DAPM_STREAM_STOP); } else { /* start delayed pop wq here for playback streams */ codec_dai->pop_wait = 1; @@ -383,9 +383,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) } } else { /* capture streams can be powered down now */ - snd_soc_dapm_stream_event(rtd, - codec_dai->driver->capture.stream_name, - SND_SOC_DAPM_STREAM_STOP); + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, + codec_dai, SND_SOC_DAPM_STREAM_STOP); }
mutex_unlock(&rtd->pcm_mutex); @@ -454,14 +453,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) cancel_delayed_work(&rtd->delayed_work); }
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dapm_stream_event(rtd, - codec_dai->driver->playback.stream_name, - SND_SOC_DAPM_STREAM_START); - else - snd_soc_dapm_stream_event(rtd, - codec_dai->driver->capture.stream_name, - SND_SOC_DAPM_STREAM_START); + snd_soc_dapm_stream_event(rtd, substream->stream, codec_dai, + SND_SOC_DAPM_STREAM_START);
snd_soc_dai_digital_mute(codec_dai, 0);
Neater and avoids warnings when used in other places where const strings are desired.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- include/sound/soc-dapm.h | 8 ++++---- include/sound/soc.h | 2 +- sound/soc/soc-core.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index c32c521..91eb812 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -445,8 +445,8 @@ struct snd_soc_dapm_route {
/* dapm audio path between two widgets */ struct snd_soc_dapm_path { - char *name; - char *long_name; + const char *name; + const char *long_name;
/* source (input) and sink (output) widgets */ struct snd_soc_dapm_widget *source; @@ -469,8 +469,8 @@ struct snd_soc_dapm_path { /* dapm widget */ struct snd_soc_dapm_widget { enum snd_soc_dapm_type id; - char *name; /* widget name */ - char *sname; /* stream name */ + const char *name; /* widget name */ + const char *sname; /* stream name */ struct snd_soc_codec *codec; struct snd_soc_platform *platform; struct list_head list; diff --git a/include/sound/soc.h b/include/sound/soc.h index a1da298..b78f84d 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -373,7 +373,7 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); *Controls */ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, - void *data, char *long_name, + void *data, const char *long_name, const char *prefix); int snd_soc_add_codec_controls(struct snd_soc_codec *codec, const struct snd_kcontrol_new *controls, int num_controls); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 87a3c5c..bfcf5d7 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2018,7 +2018,7 @@ EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams); * Returns 0 for success, else error. */ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, - void *data, char *long_name, + void *data, const char *long_name, const char *prefix) { struct snd_kcontrol_new template;
In order to allow us to do smarter things with DAI links create DAPM widgets which directly represent the DAIs in the DAPM graph. These are automatically created from the DAIs as we probe the card with references held in both directions between the widget and the DAI.
The widgets are not made available for direct instantiation by drivers, they are created automatically from the DAIs. Drivers should be updated to create stream routes using DAPM maps rather than by annotating AIF and DAC widgets with streams.
In order to ease transition to this model from existing drivers we automatically create DAPM routes between the DAI widgets and the existing stream widgets which are started and stopped by the DAI widgets, though the old stream handling mechanism is still in place. This also has the nice effect of removing non-DAPM devices as any device with a DAI acquires a widget automatically which will allow future simplifications to the core DAPM logic.
The intention is that in future the AIF and DAI widgets will gain the ability to interact such that we are able to manage activity on individual channels independantly rather than powering up and down the entire AIF as we do currently.
Currently we only generate these for CODECs, mostly as I have no systems with non-CODEC DAPM to integrate with. It should be a simple matter of programming to add the additional hookup for these.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- include/sound/soc-dai.h | 4 ++ include/sound/soc-dapm.h | 4 ++ sound/soc/soc-core.c | 11 ++++ sound/soc/soc-dapm.c | 135 +++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 146 insertions(+), 8 deletions(-)
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 1a2b08c..d474128 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -17,6 +17,7 @@ #include <linux/list.h>
struct snd_pcm_substream; +struct snd_soc_dapm_widget;
/* * DAI hardware audio formats. @@ -238,6 +239,9 @@ struct snd_soc_dai { unsigned char pop_wait:1; unsigned char probed:1;
+ struct snd_soc_dapm_widget *playback_widget; + struct snd_soc_dapm_widget *capture_widget; + /* DAI DMA data */ void *playback_dma_data; void *capture_dma_data; diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 91eb812..e46107f 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -355,6 +355,9 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget, int num); +int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, + struct snd_soc_dai *dai); +int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
/* dapm path setup */ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm); @@ -425,6 +428,7 @@ enum snd_soc_dapm_type { snd_soc_dapm_aif_in, /* audio interface input */ snd_soc_dapm_aif_out, /* audio interface output */ snd_soc_dapm_siggen, /* signal generator */ + snd_soc_dapm_dai, /* link to DAI structure */ };
/* diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index bfcf5d7..1a0cec9 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1010,6 +1010,7 @@ static int soc_probe_codec(struct snd_soc_card *card, { int ret = 0; const struct snd_soc_codec_driver *driver = codec->driver; + struct snd_soc_dai *dai;
codec->card = card; codec->dapm.card = card; @@ -1024,6 +1025,14 @@ static int soc_probe_codec(struct snd_soc_card *card, snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets, driver->num_dapm_widgets);
+ /* Create DAPM widgets for each DAI stream */ + list_for_each_entry(dai, &dai_list, list) { + if (dai->dev != codec->dev) + continue; + + snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); + } + codec->dapm.idle_bias_off = driver->idle_bias_off;
if (driver->probe) { @@ -1500,6 +1509,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) } }
+ snd_soc_dapm_link_dai_widgets(card); + if (card->controls) snd_soc_add_card_controls(card, card->controls, card->num_controls);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 21c7b31..ebf1a60 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -53,6 +53,7 @@ static int dapm_up_seq[] = { [snd_soc_dapm_supply] = 1, [snd_soc_dapm_regulator_supply] = 1, [snd_soc_dapm_micbias] = 2, + [snd_soc_dapm_dai] = 3, [snd_soc_dapm_aif_in] = 3, [snd_soc_dapm_aif_out] = 3, [snd_soc_dapm_mic] = 4, @@ -87,6 +88,7 @@ static int dapm_down_seq[] = { [snd_soc_dapm_value_mux] = 9, [snd_soc_dapm_aif_in] = 10, [snd_soc_dapm_aif_out] = 10, + [snd_soc_dapm_dai] = 10, [snd_soc_dapm_regulator_supply] = 11, [snd_soc_dapm_supply] = 11, [snd_soc_dapm_post] = 12, @@ -366,6 +368,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, case snd_soc_dapm_regulator_supply: case snd_soc_dapm_aif_in: case snd_soc_dapm_aif_out: + case snd_soc_dapm_dai: case snd_soc_dapm_hp: case snd_soc_dapm_mic: case snd_soc_dapm_spk: @@ -523,17 +526,17 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) * for widgets so cut the prefix off * the front of the widget name. */ - snprintf(path->long_name, name_len, "%s %s", - w->name + prefix_len, + snprintf((char *)path->long_name, name_len, + "%s %s", w->name + prefix_len, w->kcontrol_news[i].name); break; case snd_soc_dapm_mixer_named_ctl: - snprintf(path->long_name, name_len, "%s", - w->kcontrol_news[i].name); + snprintf((char *)path->long_name, name_len, + "%s", w->kcontrol_news[i].name); break; }
- path->long_name[name_len - 1] = '\0'; + ((char *)path->long_name)[name_len - 1] = '\0';
path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i], wlist, path->long_name, @@ -567,7 +570,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) struct snd_soc_dapm_widget_list *wlist; int shared, wlistentries; size_t wlistsize; - char *name; + const char *name;
if (w->num_kcontrols != 1) { dev_err(dapm->dev, @@ -703,6 +706,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) switch (widget->id) { case snd_soc_dapm_adc: case snd_soc_dapm_aif_out: + case snd_soc_dapm_dai: if (widget->active) { widget->outputs = snd_soc_dapm_suspend_check(widget); return widget->outputs; @@ -774,6 +778,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) switch (widget->id) { case snd_soc_dapm_dac: case snd_soc_dapm_aif_in: + case snd_soc_dapm_dai: if (widget->active) { widget->inputs = snd_soc_dapm_suspend_check(widget); return widget->inputs; @@ -893,6 +898,13 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) return out != 0 && in != 0; }
+static int dapm_dai_check_power(struct snd_soc_dapm_widget *w) +{ + DAPM_UPDATE_STAT(w, power_checks); + + return w->active; +} + /* Check to see if an ADC has power */ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w) { @@ -2052,6 +2064,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, case snd_soc_dapm_regulator_supply: case snd_soc_dapm_aif_in: case snd_soc_dapm_aif_out: + case snd_soc_dapm_dai: list_add(&path->list, &dapm->card->paths); list_add(&path->list_sink, &wsink->sources); list_add(&path->list_source, &wsource->sinks); @@ -2735,10 +2748,10 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, return NULL; } if (dapm->codec && dapm->codec->name_prefix) - snprintf(w->name, name_len, "%s %s", + snprintf((char *)w->name, name_len, "%s %s", dapm->codec->name_prefix, widget->name); else - snprintf(w->name, name_len, "%s", widget->name); + snprintf((char *)w->name, name_len, "%s", widget->name);
switch (w->id) { case snd_soc_dapm_switch: @@ -2774,6 +2787,9 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, case snd_soc_dapm_regulator_supply: w->power_check = dapm_supply_check_power; break; + case snd_soc_dapm_dai: + w->power_check = dapm_dai_check_power; + break; default: w->power_check = dapm_always_on_check_power; break; @@ -2825,6 +2841,109 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, } EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
+int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, + struct snd_soc_dai *dai) +{ + struct snd_soc_dapm_widget template; + struct snd_soc_dapm_widget *w; + + WARN_ON(dapm->dev != dai->dev); + + memset(&template, 0, sizeof(template)); + template.reg = SND_SOC_NOPM; + + if (dai->driver->playback.stream_name) { + template.id = snd_soc_dapm_dai; + template.name = dai->driver->playback.stream_name; + template.sname = dai->driver->playback.stream_name; + + dev_dbg(dai->dev, "adding %s widget\n", + template.name); + + w = snd_soc_dapm_new_control(dapm, &template); + if (!w) { + dev_err(dapm->dev, "Failed to create %s widget\n", + dai->driver->playback.stream_name); + } + + w->priv = dai; + dai->playback_widget = w; + } + + if (dai->driver->capture.stream_name) { + template.id = snd_soc_dapm_dai; + template.name = dai->driver->capture.stream_name; + template.sname = dai->driver->capture.stream_name; + + dev_dbg(dai->dev, "adding %s widget\n", + template.name); + + w = snd_soc_dapm_new_control(dapm, &template); + if (!w) { + dev_err(dapm->dev, "Failed to create %s widget\n", + dai->driver->capture.stream_name); + } + + w->priv = dai; + dai->capture_widget = w; + } + + return 0; +} + +int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) +{ + struct snd_soc_dapm_widget *dai_w, *w; + struct snd_soc_dai *dai; + struct snd_soc_dapm_route r; + + memset(&r, 0, sizeof(r)); + + /* For each DAI widget... */ + list_for_each_entry(dai_w, &card->widgets, list) { + if (dai_w->id != snd_soc_dapm_dai) + continue; + + dai = dai_w->priv; + + /* ...find all widgets with the same stream and link them */ + list_for_each_entry(w, &card->widgets, list) { + if (w->dapm != dai_w->dapm) + continue; + + if (w->id == snd_soc_dapm_dai) + continue; + + if (!w->sname) + continue; + + if (dai->driver->playback.stream_name && + strstr(w->sname, + dai->driver->playback.stream_name)) { + r.source = dai->playback_widget->name; + r.sink = w->name; + dev_dbg(dai->dev, "%s -> %s\n", + r.source, r.sink); + + snd_soc_dapm_add_route(w->dapm, &r); + } + + if (dai->driver->capture.stream_name && + strstr(w->sname, + dai->driver->capture.stream_name)) { + r.source = w->name; + r.sink = dai->capture_widget->name; + dev_dbg(dai->dev, "%s -> %s\n", + r.source, r.sink); + + snd_soc_dapm_add_route(w->dapm, &r); + } + } + } + + return 0; +} + static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, int stream, struct snd_soc_dai *dai, int event)
On Thu, 2012-02-16 at 21:56 -0800, Mark Brown wrote:
In order to allow us to do smarter things with DAI links create DAPM widgets which directly represent the DAIs in the DAPM graph. These are automatically created from the DAIs as we probe the card with references held in both directions between the widget and the DAI.
The widgets are not made available for direct instantiation by drivers, they are created automatically from the DAIs. Drivers should be updated to create stream routes using DAPM maps rather than by annotating AIF and DAC widgets with streams.
In order to ease transition to this model from existing drivers we automatically create DAPM routes between the DAI widgets and the existing stream widgets which are started and stopped by the DAI widgets, though the old stream handling mechanism is still in place. This also has the nice effect of removing non-DAPM devices as any device with a DAI acquires a widget automatically which will allow future simplifications to the core DAPM logic.
The intention is that in future the AIF and DAI widgets will gain the ability to interact such that we are able to manage activity on individual channels independantly rather than powering up and down the entire AIF as we do currently.
Currently we only generate these for CODECs, mostly as I have no systems with non-CODEC DAPM to integrate with. It should be a simple matter of programming to add the additional hookup for these.
If I understood right, then instead of creating AIF/ADCs for codec paths now we need to create the DAI widget for each path and associate that with the DAI, right. I think I understood former (creating the dai widgets), but how does it get linked to the DAIs?
Also in dai widget would it make sense to add channel map and associate that with DAI?
On Fri, 2012-02-17 at 14:10 +0530, Vinod Koul wrote:
Also in dai widget would it make sense to add channel map and associate that with DAI?
Yeah, I think that would work. I've already started some work on the channel mapping (just associating unique PCM channel masks with DAI widgets) but I do need to upstream dynamic PCM first !
Liam
On Fri, 2012-02-17 at 14:10 +0530, Vinod Koul wrote:
On Thu, 2012-02-16 at 21:56 -0800, Mark Brown wrote:
In order to allow us to do smarter things with DAI links create DAPM widgets which directly represent the DAIs in the DAPM graph. These are automatically created from the DAIs as we probe the card with references held in both directions between the widget and the DAI.
The widgets are not made available for direct instantiation by drivers, they are created automatically from the DAIs. Drivers should be updated to create stream routes using DAPM maps rather than by annotating AIF and DAC widgets with streams.
In order to ease transition to this model from existing drivers we automatically create DAPM routes between the DAI widgets and the existing stream widgets which are started and stopped by the DAI widgets, though the old stream handling mechanism is still in place. This also has the nice effect of removing non-DAPM devices as any device with a DAI acquires a widget automatically which will allow future simplifications to the core DAPM logic.
The intention is that in future the AIF and DAI widgets will gain the ability to interact such that we are able to manage activity on individual channels independantly rather than powering up and down the entire AIF as we do currently.
Currently we only generate these for CODECs, mostly as I have no systems with non-CODEC DAPM to integrate with. It should be a simple matter of programming to add the additional hookup for these.
If I understood right, then instead of creating AIF/ADCs for codec paths now we need to create the DAI widget for each path and associate that with the DAI, right. I think I understood former (creating the dai widgets), but how does it get linked to the DAIs?
Ping...
On Wed, Feb 22, 2012 at 06:05:54PM +0530, Vinod Koul wrote:
On Fri, 2012-02-17 at 14:10 +0530, Vinod Koul wrote:
Currently we only generate these for CODECs, mostly as I have no systems with non-CODEC DAPM to integrate with. It should be a simple matter of programming to add the additional hookup for these.
If I understood right, then instead of creating AIF/ADCs for codec paths now we need to create the DAI widget for each path and associate that with the DAI, right.
Wrong, these widgets are automatically generated.
On Wed, 2012-02-22 at 12:43 +0000, Mark Brown wrote:
Wrong, these widgets are automatically generated.
Okay, looks like I got it completely wrong.
From the patche set I can see that now DAIs will have playback widget
and capture widget which will be turned ON, And your changes show me that the AIF widgets you register in wm codec will now be treated as dai widgets. So from a codec driver, how does these two get linked, who fills the playback_widget pointer in dais?
For a codec which has two DAIs and I register two AIFs how will you fill the respective dia widgets in the DAIs...
On Wed, Feb 22, 2012 at 06:31:13PM +0530, Vinod Koul wrote:
So from a codec driver, how does these two get linked, who fills the playback_widget pointer in dais?
For a codec which has two DAIs and I register two AIFs how will you fill the respective dia widgets in the DAIs...
The core initialises everything when it creates the widgets...
On Wed, 2012-02-22 at 13:29 +0000, Mark Brown wrote:
On Wed, Feb 22, 2012 at 06:31:13PM +0530, Vinod Koul wrote:
So from a codec driver, how does these two get linked, who fills the playback_widget pointer in dais?
For a codec which has two DAIs and I register two AIFs how will you fill the respective dia widgets in the DAIs...
The core initialises everything when it creates the widgets...
Looks like I am completely on tangent here :(
Sorry but I am not able to comprehend how the core created playback and capture widget in the dai, which would be now used to trigger the stream_event instead of stream name is being associated with DAPM map.
Earlier we would check the stream_name and find the widgets corresponding to this and power up, how exactly would it work now :)
On Thu, Feb 23, 2012 at 12:20:03PM +0530, Vinod Koul wrote:
Sorry but I am not able to comprehend how the core created playback and capture widget in the dai, which would be now used to trigger the stream_event instead of stream name is being associated with DAPM map.
That was essentially the entire content of the patch you're replying to... the actual creation happens in snd_soc_dapm_new_dai_widgets().
Earlier we would check the stream_name and find the widgets corresponding to this and power up, how exactly would it work now :)
See "ASoC: dapm: Convert stream events to use DAI widgets".
This means we don't need to walk through every single widget in the system for each stream event which is a bit less silly.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/soc-dapm.c | 43 +++++++++++++++++-------------------------- 1 files changed, 17 insertions(+), 26 deletions(-)
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index ebf1a60..27b56e2 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2949,38 +2949,29 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, int event) { struct snd_soc_dapm_widget *w; - const char *stream_name;
if (stream == SNDRV_PCM_STREAM_PLAYBACK) - stream_name = dai->driver->playback.stream_name; + w = dai->playback_widget; else - stream_name = dai->driver->capture.stream_name; + w = dai->capture_widget;
- if (!stream_name) + if (!w) return;
- list_for_each_entry(w, &dapm->card->widgets, list) - { - if (!w->sname || w->dapm != dapm) - continue; - dev_vdbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n", - w->name, w->sname, stream_name, event); - if (strstr(w->sname, stream_name)) { - dapm_mark_dirty(w, "stream event"); - switch(event) { - case SND_SOC_DAPM_STREAM_START: - w->active = 1; - break; - case SND_SOC_DAPM_STREAM_STOP: - w->active = 0; - break; - case SND_SOC_DAPM_STREAM_SUSPEND: - case SND_SOC_DAPM_STREAM_RESUME: - case SND_SOC_DAPM_STREAM_PAUSE_PUSH: - case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: - break; - } - } + dapm_mark_dirty(w, "stream event"); + + switch (event) { + case SND_SOC_DAPM_STREAM_START: + w->active = 1; + break; + case SND_SOC_DAPM_STREAM_STOP: + w->active = 0; + break; + case SND_SOC_DAPM_STREAM_SUSPEND: + case SND_SOC_DAPM_STREAM_RESUME: + case SND_SOC_DAPM_STREAM_PAUSE_PUSH: + case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: + break; }
dapm_power_widgets(dapm, event);
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/wm8994.c | 20 ++++++++++++++------ 1 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index b137ac9..45b8ab9 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -1473,17 +1473,17 @@ SND_SOC_DAPM_AIF_IN_E("AIF2DACR", NULL, 0, WM8994_POWER_MANAGEMENT_5, 12, 0, wm8958_aif_ev, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-SND_SOC_DAPM_AIF_IN("AIF1DACDAT", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_AIF_IN("AIF2DACDAT", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_AIF_OUT("AIF1ADCDAT", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_AIF_OUT("AIF2ADCDAT", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_IN("AIF1DACDAT", NULL, 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_IN("AIF2DACDAT", NULL, 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("AIF1ADCDAT", NULL, 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("AIF2ADCDAT", NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_MUX("AIF1DAC Mux", SND_SOC_NOPM, 0, 0, &aif1dac_mux), SND_SOC_DAPM_MUX("AIF2DAC Mux", SND_SOC_NOPM, 0, 0, &aif2dac_mux), SND_SOC_DAPM_MUX("AIF2ADC Mux", SND_SOC_NOPM, 0, 0, &aif2adc_mux),
-SND_SOC_DAPM_AIF_IN("AIF3DACDAT", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_AIF_OUT("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_IN("AIF3DACDAT", NULL, 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("AIF3ADCDAT", NULL, 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_SUPPLY("TOCLK", WM8994_CLOCKING_1, 4, 0, NULL, 0),
@@ -1598,6 +1598,14 @@ static const struct snd_soc_dapm_route intercon[] = {
{ "TOCLK", NULL, "CLK_SYS" },
+ { "AIF1DACDAT", NULL, "AIF1 Playback" }, + { "AIF2DACDAT", NULL, "AIF2 Playback" }, + { "AIF3DACDAT", NULL, "AIF3 Playback" }, + + { "AIF1 Capture", NULL, "AIF1ADCDAT" }, + { "AIF2 Capture", NULL, "AIF2ADCDAT" }, + { "AIF3 Capture", NULL, "AIF3ADCDAT" }, + /* AIF1 outputs */ { "AIF1ADC1L", NULL, "AIF1ADC1L Mixer" }, { "AIF1ADC1L Mixer", "ADC/DMIC Switch", "ADCL Mux" },
On Thu, 2012-02-16 at 21:56 -0800, Mark Brown wrote:
We never modify it and this lets us use a const string as the name without warnings.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com
include/sound/control.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/include/sound/control.h b/include/sound/control.h index b2796e8..57815f6 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -40,7 +40,7 @@ struct snd_kcontrol_new { snd_ctl_elem_iface_t iface; /* interface identifier */ unsigned int device; /* device/client number */ unsigned int subdevice; /* subdevice (substream) number */
- unsigned char *name; /* ASCII name of item */
- const unsigned char *name; /* ASCII name of item */ unsigned int index; /* index of item */ unsigned int access; /* access rights */ unsigned int count; /* count of same elements */
All
Acked-by: Liam Girdwood lrg@ti.com
I'll do some incremental updates for platform and ABE support.
Liam
participants (3)
-
Liam Girdwood
-
Mark Brown
-
Vinod Koul