aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/soc-dapm.h5
-rw-r--r--include/trace/events/asoc.h80
-rw-r--r--sound/soc/soc-dapm.c122
3 files changed, 197 insertions, 10 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index bea0c8658aa0..e3833d9f1914 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -321,6 +321,7 @@ struct snd_soc_dapm_pin;
321struct snd_soc_dapm_route; 321struct snd_soc_dapm_route;
322struct snd_soc_dapm_context; 322struct snd_soc_dapm_context;
323struct regulator; 323struct regulator;
324struct snd_soc_dapm_widget_list;
324 325
325int dapm_reg_event(struct snd_soc_dapm_widget *w, 326int dapm_reg_event(struct snd_soc_dapm_widget *w,
326 struct snd_kcontrol *kcontrol, int event); 327 struct snd_kcontrol *kcontrol, int event);
@@ -403,6 +404,10 @@ void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec);
403/* Mostly internal - should not normally be used */ 404/* Mostly internal - should not normally be used */
404void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason); 405void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason);
405 406
407/* dapm path query */
408int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
409 struct snd_soc_dapm_widget_list **list);
410
406/* dapm widget types */ 411/* dapm widget types */
407enum snd_soc_dapm_type { 412enum snd_soc_dapm_type {
408 snd_soc_dapm_input = 0, /* input pin */ 413 snd_soc_dapm_input = 0, /* input pin */
diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h
index ab26f8aa3c78..6d8efb1cc8ce 100644
--- a/include/trace/events/asoc.h
+++ b/include/trace/events/asoc.h
@@ -7,6 +7,8 @@
7#include <linux/ktime.h> 7#include <linux/ktime.h>
8#include <linux/tracepoint.h> 8#include <linux/tracepoint.h>
9 9
10#define DAPM_DIRECT "(direct)"
11
10struct snd_soc_jack; 12struct snd_soc_jack;
11struct snd_soc_codec; 13struct snd_soc_codec;
12struct snd_soc_platform; 14struct snd_soc_platform;
@@ -241,6 +243,84 @@ TRACE_EVENT(snd_soc_dapm_walk_done,
241 (int)__entry->path_checks, (int)__entry->neighbour_checks) 243 (int)__entry->path_checks, (int)__entry->neighbour_checks)
242); 244);
243 245
246TRACE_EVENT(snd_soc_dapm_output_path,
247
248 TP_PROTO(struct snd_soc_dapm_widget *widget,
249 struct snd_soc_dapm_path *path),
250
251 TP_ARGS(widget, path),
252
253 TP_STRUCT__entry(
254 __string( wname, widget->name )
255 __string( pname, path->name ? path->name : DAPM_DIRECT)
256 __string( psname, path->sink->name )
257 __field( int, path_sink )
258 __field( int, path_connect )
259 ),
260
261 TP_fast_assign(
262 __assign_str(wname, widget->name);
263 __assign_str(pname, path->name ? path->name : DAPM_DIRECT);
264 __assign_str(psname, path->sink->name);
265 __entry->path_connect = path->connect;
266 __entry->path_sink = (int)path->sink;
267 ),
268
269 TP_printk("%c%s -> %s -> %s\n",
270 (int) __entry->path_sink &&
271 (int) __entry->path_connect ? '*' : ' ',
272 __get_str(wname), __get_str(pname), __get_str(psname))
273);
274
275TRACE_EVENT(snd_soc_dapm_input_path,
276
277 TP_PROTO(struct snd_soc_dapm_widget *widget,
278 struct snd_soc_dapm_path *path),
279
280 TP_ARGS(widget, path),
281
282 TP_STRUCT__entry(
283 __string( wname, widget->name )
284 __string( pname, path->name ? path->name : DAPM_DIRECT)
285 __string( psname, path->source->name )
286 __field( int, path_source )
287 __field( int, path_connect )
288 ),
289
290 TP_fast_assign(
291 __assign_str(wname, widget->name);
292 __assign_str(pname, path->name ? path->name : DAPM_DIRECT);
293 __assign_str(psname, path->source->name);
294 __entry->path_connect = path->connect;
295 __entry->path_source = (int)path->source;
296 ),
297
298 TP_printk("%c%s <- %s <- %s\n",
299 (int) __entry->path_source &&
300 (int) __entry->path_connect ? '*' : ' ',
301 __get_str(wname), __get_str(pname), __get_str(psname))
302);
303
304TRACE_EVENT(snd_soc_dapm_connected,
305
306 TP_PROTO(int paths, int stream),
307
308 TP_ARGS(paths, stream),
309
310 TP_STRUCT__entry(
311 __field( int, paths )
312 __field( int, stream )
313 ),
314
315 TP_fast_assign(
316 __entry->paths = paths;
317 __entry->stream = stream;
318 ),
319
320 TP_printk("%s: found %d paths\n",
321 __entry->stream ? "capture" : "playback", __entry->paths)
322);
323
244TRACE_EVENT(snd_soc_jack_irq, 324TRACE_EVENT(snd_soc_jack_irq,
245 325
246 TP_PROTO(const char *name), 326 TP_PROTO(const char *name),
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index d7ee73a60ca5..214323f53956 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -705,11 +705,51 @@ static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
705 } 705 }
706} 706}
707 707
708/* add widget to list if it's not already in the list */
709static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list,
710 struct snd_soc_dapm_widget *w)
711{
712 struct snd_soc_dapm_widget_list *wlist;
713 int wlistsize, wlistentries, i;
714
715 if (*list == NULL)
716 return -EINVAL;
717
718 wlist = *list;
719
720 /* is this widget already in the list */
721 for (i = 0; i < wlist->num_widgets; i++) {
722 if (wlist->widgets[i] == w)
723 return 0;
724 }
725
726 /* allocate some new space */
727 wlistentries = wlist->num_widgets + 1;
728 wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
729 wlistentries * sizeof(struct snd_soc_dapm_widget *);
730 *list = krealloc(wlist, wlistsize, GFP_KERNEL);
731 if (*list == NULL) {
732 dev_err(w->dapm->dev, "can't allocate widget list for %s\n",
733 w->name);
734 return -ENOMEM;
735 }
736 wlist = *list;
737
738 /* insert the widget */
739 dev_dbg(w->dapm->dev, "added %s in widget list pos %d\n",
740 w->name, wlist->num_widgets);
741
742 wlist->widgets[wlist->num_widgets] = w;
743 wlist->num_widgets++;
744 return 1;
745}
746
708/* 747/*
709 * Recursively check for a completed path to an active or physically connected 748 * Recursively check for a completed path to an active or physically connected
710 * output widget. Returns number of complete paths. 749 * output widget. Returns number of complete paths.
711 */ 750 */
712static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) 751static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
752 struct snd_soc_dapm_widget_list **list)
713{ 753{
714 struct snd_soc_dapm_path *path; 754 struct snd_soc_dapm_path *path;
715 int con = 0; 755 int con = 0;
@@ -765,9 +805,23 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
765 if (path->walked) 805 if (path->walked)
766 continue; 806 continue;
767 807
808 trace_snd_soc_dapm_output_path(widget, path);
809
768 if (path->sink && path->connect) { 810 if (path->sink && path->connect) {
769 path->walked = 1; 811 path->walked = 1;
770 con += is_connected_output_ep(path->sink); 812
813 /* do we need to add this widget to the list ? */
814 if (list) {
815 int err;
816 err = dapm_list_add_widget(list, path->sink);
817 if (err < 0) {
818 dev_err(widget->dapm->dev, "could not add widget %s\n",
819 widget->name);
820 return con;
821 }
822 }
823
824 con += is_connected_output_ep(path->sink, list);
771 } 825 }
772 } 826 }
773 827
@@ -780,7 +834,8 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
780 * Recursively check for a completed path to an active or physically connected 834 * Recursively check for a completed path to an active or physically connected
781 * input widget. Returns number of complete paths. 835 * input widget. Returns number of complete paths.
782 */ 836 */
783static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) 837static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
838 struct snd_soc_dapm_widget_list **list)
784{ 839{
785 struct snd_soc_dapm_path *path; 840 struct snd_soc_dapm_path *path;
786 int con = 0; 841 int con = 0;
@@ -848,9 +903,23 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
848 if (path->walked) 903 if (path->walked)
849 continue; 904 continue;
850 905
906 trace_snd_soc_dapm_input_path(widget, path);
907
851 if (path->source && path->connect) { 908 if (path->source && path->connect) {
852 path->walked = 1; 909 path->walked = 1;
853 con += is_connected_input_ep(path->source); 910
911 /* do we need to add this widget to the list ? */
912 if (list) {
913 int err;
914 err = dapm_list_add_widget(list, path->sink);
915 if (err < 0) {
916 dev_err(widget->dapm->dev, "could not add widget %s\n",
917 widget->name);
918 return con;
919 }
920 }
921
922 con += is_connected_input_ep(path->source, list);
854 } 923 }
855 } 924 }
856 925
@@ -859,6 +928,39 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
859 return con; 928 return con;
860} 929}
861 930
931/**
932 * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets.
933 * @dai: the soc DAI.
934 * @stream: stream direction.
935 * @list: list of active widgets for this stream.
936 *
937 * Queries DAPM graph as to whether an valid audio stream path exists for
938 * the initial stream specified by name. This takes into account
939 * current mixer and mux kcontrol settings. Creates list of valid widgets.
940 *
941 * Returns the number of valid paths or negative error.
942 */
943int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
944 struct snd_soc_dapm_widget_list **list)
945{
946 struct snd_soc_card *card = dai->card;
947 int paths;
948
949 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
950 dapm_reset(card);
951
952 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
953 paths = is_connected_output_ep(dai->playback_widget, list);
954 else
955 paths = is_connected_input_ep(dai->playback_widget, list);
956
957 trace_snd_soc_dapm_connected(paths, stream);
958 dapm_clear_walk(&card->dapm);
959 mutex_unlock(&card->dapm_mutex);
960
961 return paths;
962}
963
862/* 964/*
863 * Handler for generic register modifier widget. 965 * Handler for generic register modifier widget.
864 */ 966 */
@@ -915,9 +1017,9 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
915 1017
916 DAPM_UPDATE_STAT(w, power_checks); 1018 DAPM_UPDATE_STAT(w, power_checks);
917 1019
918 in = is_connected_input_ep(w); 1020 in = is_connected_input_ep(w, NULL);
919 dapm_clear_walk(w->dapm); 1021 dapm_clear_walk(w->dapm);
920 out = is_connected_output_ep(w); 1022 out = is_connected_output_ep(w, NULL);
921 dapm_clear_walk(w->dapm); 1023 dapm_clear_walk(w->dapm);
922 return out != 0 && in != 0; 1024 return out != 0 && in != 0;
923} 1025}
@@ -940,7 +1042,7 @@ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
940 DAPM_UPDATE_STAT(w, power_checks); 1042 DAPM_UPDATE_STAT(w, power_checks);
941 1043
942 if (w->active) { 1044 if (w->active) {
943 in = is_connected_input_ep(w); 1045 in = is_connected_input_ep(w, NULL);
944 dapm_clear_walk(w->dapm); 1046 dapm_clear_walk(w->dapm);
945 return in != 0; 1047 return in != 0;
946 } else { 1048 } else {
@@ -956,7 +1058,7 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
956 DAPM_UPDATE_STAT(w, power_checks); 1058 DAPM_UPDATE_STAT(w, power_checks);
957 1059
958 if (w->active) { 1060 if (w->active) {
959 out = is_connected_output_ep(w); 1061 out = is_connected_output_ep(w, NULL);
960 dapm_clear_walk(w->dapm); 1062 dapm_clear_walk(w->dapm);
961 return out != 0; 1063 return out != 0;
962 } else { 1064 } else {
@@ -1558,9 +1660,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
1558 if (!buf) 1660 if (!buf)
1559 return -ENOMEM; 1661 return -ENOMEM;
1560 1662
1561 in = is_connected_input_ep(w); 1663 in = is_connected_input_ep(w, NULL);
1562 dapm_clear_walk(w->dapm); 1664 dapm_clear_walk(w->dapm);
1563 out = is_connected_output_ep(w); 1665 out = is_connected_output_ep(w, NULL);
1564 dapm_clear_walk(w->dapm); 1666 dapm_clear_walk(w->dapm);
1565 1667
1566 ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", 1668 ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",