ASoC: dapm - improvements to path finder - SQUASH
Signed-off-by: Liam Girdwood <lrg@ti.com>
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 25b2acf..9e59c96 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -316,6 +316,7 @@
struct snd_soc_dapm_pin;
struct snd_soc_dapm_route;
struct snd_soc_dapm_context;
+struct snd_soc_dapm_widget_list;
int dapm_reg_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
@@ -389,6 +390,13 @@
int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
const char *pin);
+/* dapm path query */
+int snd_soc_dapm_get_connected_widgets_type(struct snd_soc_dapm_context *dapm,
+ const char *stream_name, struct snd_soc_dapm_widget_list **list,
+ int stream, enum snd_soc_dapm_type type);
+int snd_soc_dapm_get_connected_widgets_name(struct snd_soc_dapm_context *dapm,
+ const char *name, struct snd_soc_dapm_widget_list **list, int stream);
+
/* dapm widget types */
enum snd_soc_dapm_type {
snd_soc_dapm_input = 0, /* input pin */
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 424836e..2ee137a 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -223,12 +223,94 @@
dapm_clear_walk(dapm);
}
+static int dapm_add_unique_widget(struct snd_soc_dapm_context *dapm,
+ struct snd_soc_dapm_widget_list **list, struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dapm_widget_list *wlist;
+ int wlistsize, wlistentries, i;
+
+ /* is the list empty ? */
+ if (*list == NULL) {
+
+ wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
+ sizeof(struct snd_soc_dapm_widget *);
+ *list = kzalloc(wlistsize, GFP_KERNEL);
+ if (*list == NULL) {
+ dev_err(dapm->dev, "can't allocate widget list for %s\n", w->name);
+ return -ENOMEM;
+ }
+ } else {
+
+ wlist = *list;
+ /* is this widget already in the list */
+ for (i = 0; i < wlist->num_widgets; i++) {
+ if (wlist->widgets[i] == w)
+ return 0;
+ }
+
+ wlistentries = wlist->num_widgets + 1;
+ wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
+ wlistentries * sizeof(struct snd_soc_dapm_widget *);
+ *list = krealloc(wlist, wlistsize, GFP_KERNEL);
+ if (*list == NULL) {
+ dev_err(dapm->dev, "can't allocate widget list for %s\n", w->name);
+ return -ENOMEM;
+ }
+ }
+ wlist = *list;
+
+ /* insert the widget */
+ dev_dbg(dapm->dev, "added %s in widget list pos %d\n",
+ w->name, wlist->num_widgets);
+ wlist->widgets[wlist->num_widgets] = w;
+ wlist->num_widgets++;
+ return 1;
+}
+
+static int is_output_widget_ep(struct snd_soc_dapm_widget *widget)
+{
+ switch (widget->id) {
+ case snd_soc_dapm_adc:
+ case snd_soc_dapm_aif_out:
+ return 1;
+ case snd_soc_dapm_output:
+ if (widget->connected && !widget->ext)
+ return 1;
+ else
+ return 0;
+ case snd_soc_dapm_hp:
+ case snd_soc_dapm_spk:
+ case snd_soc_dapm_line:
+ return !list_empty(&widget->sources);
+ default:
+ return 0;
+ }
+}
+
+static int is_input_widget_ep(struct snd_soc_dapm_widget *widget)
+{
+ switch (widget->id) {
+ case snd_soc_dapm_dac:
+ case snd_soc_dapm_aif_in:
+ return 1;
+ case snd_soc_dapm_input:
+ if (widget->connected && !widget->ext)
+ return 1;
+ else
+ return 0;
+ case snd_soc_dapm_mic:
+ return !list_empty(&widget->sources);
+ default:
+ return 0;
+ }
+}
+
/*
* find all the paths between source and sink
*/
-static int dapm_find_playback_paths (struct snd_soc_dapm_context *dapm,
- struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
- int hops)
+static int dapm_find_playback_paths(struct snd_soc_dapm_context *dapm,
+ struct snd_soc_dapm_widget *root,
+ struct snd_soc_dapm_widget_list **list, int hops)
{
struct list_head *lp;
struct snd_soc_dapm_path *path;
@@ -237,24 +319,24 @@
if (hops > PATH_MAX_HOPS)
return 0;
- if (source == sink) {
- dev_dbg(dapm->dev," ! %d: valid route found\n", hops);
+ if (is_output_widget_ep(root) && hops != 1) {
+ dev_dbg(dapm->dev," ! %d: valid playback route found\n", hops);
dapm->num_valid_paths++;
return 1;
}
- if (source->hops && source->hops <= hops)
+ if (root->hops && root->hops <= hops)
return 0;
- source->hops = hops;
+ root->hops = hops;
/* check all the output paths on this source widget by walking
* from source to sink */
- list_for_each(lp, &source->sinks) {
+ list_for_each(lp, &root->sinks) {
path = list_entry(lp, struct snd_soc_dapm_path, list_source);
dev_dbg(dapm->dev," %c %d: %s -> %s -> %s\n",
path->connect ? '*' : ' ', hops,
- source->name, path->name, path->sink->name);
+ root->name, path->name, path->sink->name);
/* been here before ? */
if (path->length && path->length <= hops)
@@ -262,8 +344,12 @@
/* check down the next path if connected */
if (path->sink && path->connect &&
- dapm_find_playback_paths(dapm, path->sink, sink, hops + 1)) {
+ dapm_find_playback_paths(dapm, path->sink, list, hops + 1)) {
path->length = hops;
+
+ /* add widget to list */
+ dapm_add_unique_widget(dapm, list, path->sink);
+
if (!dist || dist > path->length)
dist = path->length;
}
@@ -272,9 +358,9 @@
return dist;
}
-static int dapm_find_capture_paths (struct snd_soc_dapm_context *dapm,
- struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
- int hops)
+static int dapm_find_capture_paths(struct snd_soc_dapm_context *dapm,
+ struct snd_soc_dapm_widget *root,
+ struct snd_soc_dapm_widget_list **list, int hops)
{
struct list_head *lp;
struct snd_soc_dapm_path *path;
@@ -283,24 +369,24 @@
if (hops > PATH_MAX_HOPS)
return 0;
- if (source == sink) {
- dev_dbg(dapm->dev," ! %d: valid route found\n", hops);
+ if (is_input_widget_ep(root) && hops != 1) {
+ dev_dbg(dapm->dev," ! %d: valid capture route found\n", hops);
dapm->num_valid_paths++;
return 1;
}
- if (sink->hops && sink->hops <= hops)
+ if (root->hops && root->hops <= hops)
return 0;
- sink->hops = hops;
+ root->hops = hops;
/* check all the output paths on this source widget by walking from
* sink to source */
- list_for_each(lp, &sink->sources) {
+ list_for_each(lp, &root->sources) {
path = list_entry(lp, struct snd_soc_dapm_path, list_sink);
dev_dbg(dapm->dev," %c %d: %s <- %s <- %s\n",
path->connect ? '*' : ' ', hops,
- sink->name, path->name, path->source->name);
+ root->name, path->name, path->source->name);
/* been here before ? */
if (path->length && path->length <= hops)
@@ -308,8 +394,12 @@
/* check down the next path if connected */
if (path->source && path->connect &&
- dapm_find_capture_paths(dapm, source, path->source, hops + 1)) {
+ dapm_find_capture_paths(dapm, path->source, list, hops + 1)) {
path->length = hops;
+
+ /* add widget to list */
+ dapm_add_unique_widget(dapm, list, path->source);
+
if (!dist || dist > path->length)
dist = path->length;
}
@@ -322,79 +412,107 @@
* traverse the tree from sink to source via the shortest path
*/
static int dapm_get_playback_paths(struct snd_soc_dapm_context *dapm,
- struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink)
+ struct snd_soc_dapm_widget *root,
+ struct snd_soc_dapm_widget_list **list)
{
- dev_dbg(dapm->dev, "Playback: checking path from %s to %s\n",
- source->name, sink->name);
-
- dapm->num_valid_paths = 0;
- dapm_find_playback_paths(dapm, source, sink, 1);
+ dev_dbg(dapm->dev, "Playback: checking paths from %s\n",root->name);
+ dapm_find_playback_paths(dapm, root, list, 1);
return dapm->num_valid_paths;
}
static int dapm_get_capture_paths(struct snd_soc_dapm_context *dapm,
- struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink)
+ struct snd_soc_dapm_widget *root,
+ struct snd_soc_dapm_widget_list **list)
{
- dev_dbg(dapm->dev, "check capture path to %s from %s\n",
- source->name, sink->name);
-
- dapm->num_valid_paths = 0;
- dapm_find_capture_paths(dapm, sink, source, 1);
+ dev_dbg(dapm->dev, "Capture: checking paths to %s\n", root->name);
+ dapm_find_capture_paths(dapm, root, list, 1);
return dapm->num_valid_paths;
}
/**
- * snd_soc_dapm_query_path - query audio path
- * @dapm: the dapm context
- * @source_name: source widget name
- * @sink_name: sink widget name
- * @stream: stream direction
+ * snd_soc_dapm_get_connected_widgets_type - query audio path and it's widgets.
+ * @dapm: the dapm context.
+ * @stream_name: stream name.
+ * @list: list of active widgets for this stream.
+ * @stream: stream direction.
+ * @type: Initial widget type.
*
- * Queries DAPM graph as to whether an valid audio stream path exists between
- * the source and sink widgets specified. This takes into account current
- * mixer and mux kcontrol settings.
+ * Queries DAPM graph as to whether an valid audio stream path exists for
+ * the DAPM stream and initial widget type specified. This takes into account
+ * current mixer and mux kcontrol settings. Creates list of valid widgets.
*
* Returns the number of valid paths or negative error.
*/
-int snd_soc_dapm_query_path(struct snd_soc_dapm_context *dapm,
- const char *source_name, const char *sink_name, int stream)
+int snd_soc_dapm_get_connected_widgets_type(struct snd_soc_dapm_context *dapm,
+ const char *stream_name, struct snd_soc_dapm_widget_list **list,
+ int stream, enum snd_soc_dapm_type type)
{
- struct snd_soc_dapm_widget *sink = NULL, *source = NULL;
- struct list_head *l = NULL;
- int routes;
+ struct snd_soc_dapm_widget *w;
+ int paths;
- /* find source and sink widgets */
- list_for_each(l, &dapm->card->widgets) {
- struct snd_soc_dapm_widget *w =
- list_entry(l, struct snd_soc_dapm_widget, list);
+ /* get stream root widget AIF, DAC or ADC from stream string and direction */
+ list_for_each_entry(w, &dapm->card->widgets, list) {
- if (!source && !strcmp(w->name, source_name)) {
- source = w;
+ if (!w->sname)
continue;
- }
- if (!sink && !strcmp(w->name, sink_name))
- sink = w;
- }
+ if (w->id != type)
+ continue;
- if (!source) {
- dev_err(dapm->dev, "can't find source widget: %s\n", source_name);
- return -EINVAL;
+ if (strstr(w->sname, stream_name))
+ goto found;
}
- if (!sink) {
- dev_err(dapm->dev, "can't find sink widget: %s\n", sink_name);
- return -EINVAL;
- }
+ dev_err(dapm->dev, "root widget not found\n");
+ return 0;
+found:
+ dapm->num_valid_paths = 0;
+ *list = NULL;
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
- routes = dapm_get_playback_paths(dapm, source, sink);
+ paths = dapm_get_playback_paths(dapm, w, list);
else
- routes = dapm_get_capture_paths(dapm, source, sink);
+ paths = dapm_get_capture_paths(dapm, w, list);
dapm_clear_paths(dapm);
- return routes;
+ return paths;
}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_query_path);
+/**
+ * snd_soc_dapm_get_connected_widgets_name - query audio path and it's widgets.
+ * @dapm: the dapm context.
+ * @name: initial widget name.
+ * @list: list of active widgets for this stream.
+ * @stream: stream direction.
+ *
+ * Queries DAPM graph as to whether an valid audio stream path exists for
+ * the initial widget specified by name. This takes into account
+ * current mixer and mux kcontrol settings. Creates list of valid widgets.
+ *
+ * Returns the number of valid paths or negative error.
+ */
+int snd_soc_dapm_get_connected_widgets_name(struct snd_soc_dapm_context *dapm,
+ const char *name, struct snd_soc_dapm_widget_list **list, int stream)
+{
+ struct snd_soc_dapm_widget *w;
+ int paths;
+
+ /* get stream root widget AIF, DAC or ADC from stream string and direction */
+ list_for_each_entry(w, &dapm->card->widgets, list) {
+
+ if (strstr(w->name, name))
+ goto found;
+ }
+ dev_err(dapm->dev, "root widget %s not found\n", name);
+ return 0;
+
+found:
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ paths = dapm_get_playback_paths(dapm, w, list);
+ else
+ paths = dapm_get_capture_paths(dapm, w, list);
+
+ dapm_clear_paths(dapm);
+ return paths;
+}
/**
* snd_soc_dapm_set_bias_level - set the bias level for the system