@@ -269,6 +269,10 @@ int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsourc
269269 is_virtual_widget (sdev , sink_widget -> widget , __func__ ))
270270 return 0 ;
271271
272+ /* skip route if source/sink widget is not set up */
273+ if (!src_widget -> use_count || !sink_widget -> use_count )
274+ return 0 ;
275+
272276 /* find route matching source and sink widgets */
273277 list_for_each_entry (sroute , & sdev -> route_list , list )
274278 if (sroute -> src_widget == src_widget && sroute -> sink_widget == sink_widget ) {
@@ -297,10 +301,10 @@ int sof_route_setup(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *wsourc
297301 return 0 ;
298302}
299303
304+ static bool sof_widget_in_same_direction (struct snd_sof_widget * swidget , int dir );
300305static int sof_setup_pipeline_connections (struct snd_sof_dev * sdev ,
301306 struct snd_soc_dapm_widget_list * list , int dir )
302307{
303- const struct sof_ipc_tplg_ops * tplg_ops = sof_ipc_get_ops (sdev , tplg );
304308 struct snd_soc_dapm_widget * widget ;
305309 struct snd_sof_route * sroute ;
306310 struct snd_soc_dapm_path * p ;
@@ -315,14 +319,30 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
315319 */
316320 if (dir == SNDRV_PCM_STREAM_PLAYBACK ) {
317321 for_each_dapm_widgets (list , i , widget ) {
322+ struct snd_sof_widget * src_widget , * sink_widget ;
323+
318324 if (!widget -> dobj .private )
319325 continue ;
320326
321327 snd_soc_dapm_widget_for_each_sink_path (widget , p ) {
322328 if (!widget_in_list (list , p -> sink ))
323329 continue ;
330+ src_widget = widget -> dobj .private ;
324331
325332 if (p -> sink -> dobj .private ) {
333+ sink_widget = p -> sink -> dobj .private ;
334+
335+ /*
336+ * skip if source and sink are in different directions
337+ * (ex. playback and echo ref) if the direction is set in
338+ * topology. These will be set up later. It is enough to
339+ * check if the direction_valid is set for one of the
340+ * widgets as all widgets will have the direction set
341+ * in topology if one is set.
342+ */
343+ if (sink_widget -> spipe -> direction_valid &&
344+ !sof_widget_in_same_direction (sink_widget , src_widget -> spipe -> direction ))
345+ continue ;
326346 ret = sof_route_setup (sdev , widget , p -> sink );
327347 if (ret < 0 )
328348 return ret ;
@@ -331,14 +351,32 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
331351 }
332352 } else {
333353 for_each_dapm_widgets (list , i , widget ) {
354+ struct snd_sof_widget * src_widget , * sink_widget ;
355+
334356 if (!widget -> dobj .private )
335357 continue ;
336358
337359 snd_soc_dapm_widget_for_each_source_path (widget , p ) {
338360 if (!widget_in_list (list , p -> source ))
339361 continue ;
340362
363+ sink_widget = widget -> dobj .private ;
364+
341365 if (p -> source -> dobj .private ) {
366+ src_widget = p -> source -> dobj .private ;
367+
368+ /*
369+ * skip if source and sink are in different directions
370+ * (ex. playback and echo ref) if the direction is set in
371+ * topology. These will be set up later. It is enough to
372+ * check if the direction_valid is set for one of the
373+ * widgets as all widgets will have the direction set
374+ * in topology if one is set.
375+ */
376+ if (sink_widget -> spipe -> direction_valid &&
377+ !sof_widget_in_same_direction (sink_widget , src_widget -> spipe -> direction ))
378+ continue ;
379+
342380 ret = sof_route_setup (sdev , p -> source , widget );
343381 if (ret < 0 )
344382 return ret ;
@@ -355,7 +393,6 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
355393 */
356394 list_for_each_entry (sroute , & sdev -> route_list , list ) {
357395 bool src_widget_in_dapm_list , sink_widget_in_dapm_list ;
358- struct snd_sof_widget * swidget ;
359396
360397 if (sroute -> setup )
361398 continue ;
@@ -364,63 +401,69 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
364401 sink_widget_in_dapm_list = widget_in_list (list , sroute -> sink_widget -> widget );
365402
366403 /*
367- * if both source and sink are in the DAPM list, the route must already have been
368- * set up above. And if neither are in the DAPM list, the route shouldn't be
369- * handled now.
404+ * no need to set up the route if both the source and sink widgets are not in the
405+ * DAPM list
370406 */
371- if (src_widget_in_dapm_list == sink_widget_in_dapm_list )
407+ if (! src_widget_in_dapm_list && ! sink_widget_in_dapm_list )
372408 continue ;
373409
374410 /*
375- * At this point either the source widget or the sink widget is in the DAPM list
376- * with a route that might need to be set up. Check the use_count of the widget
377- * that is not in the DAPM list to confirm if it is in use currently before setting
378- * up the route.
411+ * set up the route only if both the source and sink widgets are in the DAPM list
412+ * but are in different directions. The ones in the same direction would already
413+ * have been set up in the previous loop.
379414 */
380- if (src_widget_in_dapm_list )
381- swidget = sroute -> sink_widget ;
382- else
383- swidget = sroute -> src_widget ;
415+ if (src_widget_in_dapm_list && sink_widget_in_dapm_list ) {
416+ struct snd_sof_widget * src_widget , * sink_widget ;
384417
385- scoped_guard (mutex , & swidget -> setup_mutex ) {
386- if (!swidget -> use_count )
387- continue ;
418+ src_widget = sroute -> src_widget -> widget -> dobj .private ;
419+ sink_widget = sroute -> sink_widget -> widget -> dobj .private ;
388420
389- if (tplg_ops && tplg_ops -> route_setup ) {
390- /*
391- * this route will get freed when either the
392- * source widget or the sink widget is freed
393- * during hw_free
394- */
395- ret = tplg_ops -> route_setup (sdev , sroute );
396- if (!ret )
397- sroute -> setup = true;
398- }
421+ /*
422+ * it is enough to check if the direction_valid is set for one of the
423+ * widgets as all widgets will have the direction set in topology if one
424+ * is set.
425+ */
426+ if (src_widget && sink_widget &&
427+ src_widget -> spipe -> direction_valid &&
428+ sof_widget_in_same_direction (sink_widget , src_widget -> spipe -> direction ))
429+ continue ;
399430 }
400431
432+ ret = sof_route_setup (sdev , sroute -> src_widget -> widget ,
433+ sroute -> sink_widget -> widget );
434+
401435 if (ret < 0 )
402436 return ret ;
403437 }
404438
405439 return 0 ;
406440}
407441
442+ static bool sof_widget_in_same_direction (struct snd_sof_widget * swidget , int dir )
443+ {
444+ if (swidget -> spipe -> direction == dir )
445+ return true;
446+
447+ return false;
448+ }
449+
408450static void
409451sof_unprepare_widgets_in_path (struct snd_sof_dev * sdev , struct snd_soc_dapm_widget * widget ,
410- struct snd_soc_dapm_widget_list * list )
452+ struct snd_soc_dapm_widget_list * list , int dir )
411453{
412454 const struct sof_ipc_tplg_ops * tplg_ops = sof_ipc_get_ops (sdev , tplg );
413455 struct snd_sof_widget * swidget = widget -> dobj .private ;
414456 const struct sof_ipc_tplg_widget_ops * widget_ops ;
415457 struct snd_soc_dapm_path * p ;
416458
417- /* skip if the widget is in use or if it is already unprepared */
418- if (!swidget || !swidget -> prepared || swidget -> use_count > 0 ||
419- is_virtual_widget (sdev , widget , __func__ ))
459+ if (!swidget || is_virtual_widget (sdev , widget , __func__ ))
420460 goto sink_unprepare ;
421461
422- /* skip aggregated DAIs */
423- if (is_aggregated_dai (swidget ))
462+ if (swidget -> spipe -> direction_valid && !sof_widget_in_same_direction (swidget , dir ))
463+ return ;
464+
465+ /* skip widgets in use, those already unprepared or aggregated DAIs */
466+ if (!swidget -> prepared || swidget -> use_count > 0 || is_aggregated_dai (swidget ))
424467 goto sink_unprepare ;
425468
426469 widget_ops = tplg_ops ? tplg_ops -> widget : NULL ;
@@ -435,9 +478,10 @@ sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widg
435478 snd_soc_dapm_widget_for_each_sink_path (widget , p ) {
436479 if (!widget_in_list (list , p -> sink ))
437480 continue ;
481+
438482 if (!p -> walking && p -> sink -> dobj .private ) {
439483 p -> walking = true;
440- sof_unprepare_widgets_in_path (sdev , p -> sink , list );
484+ sof_unprepare_widgets_in_path (sdev , p -> sink , list , dir );
441485 p -> walking = false;
442486 }
443487 }
@@ -456,18 +500,21 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget
456500 struct snd_soc_dapm_path * p ;
457501 int ret ;
458502
459- if (is_virtual_widget (sdev , widget , __func__ ))
503+ dev_dbg (sdev -> dev , "%s: preparing widget %s id %d\n" ,
504+ __func__ , widget -> name , widget -> id );
505+
506+ if (is_virtual_widget (sdev , widget , __func__ ) || !swidget )
460507 goto sink_prepare ;
461508
462509 widget_ops = tplg_ops ? tplg_ops -> widget : NULL ;
463510 if (!widget_ops )
464511 return 0 ;
465512
466- if (! swidget || ! widget_ops [ widget -> id ]. ipc_prepare || swidget -> prepared )
467- goto sink_prepare ;
513+ if (swidget -> spipe -> direction_valid && ! sof_widget_in_same_direction ( swidget , dir ) )
514+ return 0 ;
468515
469- /* skip aggregated DAIs */
470- if ( is_aggregated_dai (swidget ))
516+ if (! widget_ops [ widget -> id ]. ipc_prepare || swidget -> prepared ||
517+ is_aggregated_dai (swidget ))
471518 goto sink_prepare ;
472519
473520 /* prepare the source widget */
@@ -485,6 +532,7 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget
485532 snd_soc_dapm_widget_for_each_sink_path (widget , p ) {
486533 if (!widget_in_list (list , p -> sink ))
487534 continue ;
535+
488536 if (!p -> walking && p -> sink -> dobj .private ) {
489537 p -> walking = true;
490538 ret = sof_prepare_widgets_in_path (sdev , p -> sink , fe_params ,
@@ -514,23 +562,25 @@ static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dap
514562 int dir , struct snd_sof_pcm * spcm )
515563{
516564 struct snd_soc_dapm_widget_list * list = spcm -> stream [dir ].list ;
517- struct snd_sof_widget * swidget ;
565+ struct snd_sof_widget * swidget = widget -> dobj . private ;
518566 struct snd_soc_dapm_path * p ;
519567 int err ;
520568 int ret = 0 ;
521569
522- if (is_virtual_widget (sdev , widget , __func__ ))
570+ if (is_virtual_widget (sdev , widget , __func__ ) || ! swidget )
523571 goto sink_free ;
524572
525- swidget = widget -> dobj .private ;
573+ /* skip aggregated DAIs */
574+ if (swidget -> spipe -> direction_valid && !sof_widget_in_same_direction (swidget , dir ))
575+ return 0 ;
526576
527- /* no need to free aggregated DAI widgets */
528- if (swidget && !is_aggregated_dai (swidget )) {
529- err = sof_widget_free (sdev , swidget );
530- if (err < 0 )
531- ret = err ;
532- }
577+ if (is_aggregated_dai (swidget ))
578+ goto sink_free ;
533579
580+ err = sof_widget_free (sdev , widget -> dobj .private );
581+ if (err < 0 )
582+ ret = err ;
583+ sink_free :
534584 /* free all widgets in the sink paths even in case of error to keep use counts balanced */
535585 snd_soc_dapm_widget_for_each_sink_path (widget , p ) {
536586 if (!p -> walking ) {
@@ -570,6 +620,10 @@ static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_d
570620 if (swidget ) {
571621 int i ;
572622
623+ /* skip aggregated DAIs */
624+ if (swidget -> spipe -> direction_valid && !sof_widget_in_same_direction (swidget , dir ))
625+ return 0 ;
626+
573627 if (is_aggregated_dai (swidget ))
574628 goto sink_setup ;
575629
@@ -635,15 +689,14 @@ sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
635689 return 0 ;
636690
637691 for_each_dapm_widgets (list , i , widget ) {
638- if (is_virtual_widget (sdev , widget , __func__ ))
639- continue ;
640-
641- /* starting widget for playback is AIF type */
642- if (dir == SNDRV_PCM_STREAM_PLAYBACK && widget -> id != snd_soc_dapm_aif_in )
692+ /* starting widget for playback is of AIF or snd_soc_dapm_input type */
693+ if (dir == SNDRV_PCM_STREAM_PLAYBACK && (widget -> id != snd_soc_dapm_aif_in &&
694+ widget -> id != snd_soc_dapm_input ))
643695 continue ;
644696
645697 /* starting widget for capture is DAI type */
646- if (dir == SNDRV_PCM_STREAM_CAPTURE && widget -> id != snd_soc_dapm_dai_out )
698+ if (dir == SNDRV_PCM_STREAM_CAPTURE && widget -> id != snd_soc_dapm_dai_out &&
699+ widget -> id != snd_soc_dapm_output )
647700 continue ;
648701
649702 switch (op ) {
@@ -673,7 +726,7 @@ sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
673726 break ;
674727 }
675728 case SOF_WIDGET_UNPREPARE :
676- sof_unprepare_widgets_in_path (sdev , widget , list );
729+ sof_unprepare_widgets_in_path (sdev , widget , list , dir );
677730 break ;
678731 default :
679732 dev_err (sdev -> dev , "Invalid widget op %d\n" , op );
@@ -920,29 +973,41 @@ struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp,
920973 return NULL ;
921974}
922975
923- /* find widget by stream name and direction */
924- struct snd_sof_widget *
925- snd_sof_find_swidget_sname (struct snd_soc_component * scomp ,
926- const char * pcm_name , int dir )
976+ static struct snd_sof_widget * snd_sof_find_swidget_sname_type (struct snd_soc_component * scomp ,
977+ const char * sname ,
978+ enum snd_soc_dapm_type type )
927979{
928980 struct snd_sof_dev * sdev = snd_soc_component_get_drvdata (scomp );
929981 struct snd_sof_widget * swidget ;
930- enum snd_soc_dapm_type type ;
931-
932- if (dir == SNDRV_PCM_STREAM_PLAYBACK )
933- type = snd_soc_dapm_aif_in ;
934- else
935- type = snd_soc_dapm_aif_out ;
936982
937983 list_for_each_entry (swidget , & sdev -> widget_list , list ) {
938- if (!strcmp (pcm_name , swidget -> widget -> sname ) &&
939- swidget -> id == type )
984+ if (!strcmp (sname , swidget -> widget -> sname ) && swidget -> id == type )
940985 return swidget ;
941986 }
942987
943988 return NULL ;
944989}
945990
991+ /* find widget by stream name and direction */
992+ struct snd_sof_widget *
993+ snd_sof_find_swidget_sname (struct snd_soc_component * scomp ,
994+ const char * pcm_name , int dir )
995+ {
996+ if (dir == SNDRV_PCM_STREAM_PLAYBACK ) {
997+ struct snd_sof_widget * swidget ;
998+
999+ /* first look for an aif_in type widget */
1000+ swidget = snd_sof_find_swidget_sname_type (scomp , pcm_name , snd_soc_dapm_aif_in );
1001+ if (swidget )
1002+ return swidget ;
1003+
1004+ /* if not found, look for an input type widget */
1005+ return snd_sof_find_swidget_sname_type (scomp , pcm_name , snd_soc_dapm_input );
1006+ }
1007+
1008+ return snd_sof_find_swidget_sname_type (scomp , pcm_name , snd_soc_dapm_aif_out );
1009+ }
1010+
9461011struct snd_sof_dai * snd_sof_find_dai (struct snd_soc_component * scomp ,
9471012 const char * name )
9481013{
0 commit comments