@@ -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,39 @@ 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 )
305+ {
306+ if (swidget -> spipe -> direction == dir )
307+ return true;
308+
309+ return false;
310+ }
311+
312+ static int sof_set_up_same_dir_widget_routes (struct snd_sof_dev * sdev ,
313+ struct snd_soc_dapm_widget * wsource ,
314+ struct snd_soc_dapm_widget * wsink )
315+ {
316+ struct snd_sof_widget * src_widget = wsource -> dobj .private ;
317+ struct snd_sof_widget * sink_widget = wsink -> dobj .private ;
318+
319+ /*
320+ * skip setting up route if source and sink are in different directions (ex. playback and
321+ * echo ref) if the direction is set in topology. These will be set up later. It is enough
322+ * to check if the direction_valid is set for one of the widgets as all widgets will have
323+ * the direction set in topology if one is set.
324+ */
325+ if (sink_widget -> spipe -> direction_valid &&
326+ !sof_widget_in_same_direction (sink_widget , src_widget -> spipe -> direction ))
327+ return 0 ;
328+
329+ return sof_route_setup (sdev , wsource , wsink );
330+ }
331+
332+
333+
300334static int sof_setup_pipeline_connections (struct snd_sof_dev * sdev ,
301335 struct snd_soc_dapm_widget_list * list , int dir )
302336{
303- const struct sof_ipc_tplg_ops * tplg_ops = sof_ipc_get_ops (sdev , tplg );
304337 struct snd_soc_dapm_widget * widget ;
305338 struct snd_sof_route * sroute ;
306339 struct snd_soc_dapm_path * p ;
@@ -323,7 +356,7 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
323356 continue ;
324357
325358 if (p -> sink -> dobj .private ) {
326- ret = sof_route_setup (sdev , widget , p -> sink );
359+ ret = sof_set_up_same_dir_widget_routes (sdev , widget , p -> sink );
327360 if (ret < 0 )
328361 return ret ;
329362 }
@@ -339,7 +372,7 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
339372 continue ;
340373
341374 if (p -> source -> dobj .private ) {
342- ret = sof_route_setup (sdev , p -> source , widget );
375+ ret = sof_set_up_same_dir_widget_routes (sdev , p -> source , widget );
343376 if (ret < 0 )
344377 return ret ;
345378 }
@@ -355,7 +388,6 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
355388 */
356389 list_for_each_entry (sroute , & sdev -> route_list , list ) {
357390 bool src_widget_in_dapm_list , sink_widget_in_dapm_list ;
358- struct snd_sof_widget * swidget ;
359391
360392 if (sroute -> setup )
361393 continue ;
@@ -364,63 +396,64 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
364396 sink_widget_in_dapm_list = widget_in_list (list , sroute -> sink_widget -> widget );
365397
366398 /*
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.
399+ * no need to set up the route if both the source and sink widgets are not in the
400+ * DAPM list
370401 */
371- if (src_widget_in_dapm_list == sink_widget_in_dapm_list )
402+ if (! src_widget_in_dapm_list && ! sink_widget_in_dapm_list )
372403 continue ;
373404
374405 /*
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.
406+ * set up the route only if both the source and sink widgets are in the DAPM list
407+ * but are in different directions. The ones in the same direction would already
408+ * have been set up in the previous loop.
379409 */
380- if (src_widget_in_dapm_list )
381- swidget = sroute -> sink_widget ;
382- else
383- swidget = sroute -> src_widget ;
410+ if (src_widget_in_dapm_list && sink_widget_in_dapm_list ) {
411+ struct snd_sof_widget * src_widget , * sink_widget ;
384412
385- scoped_guard (mutex , & swidget -> setup_mutex ) {
386- if (!swidget -> use_count )
387- continue ;
413+ src_widget = sroute -> src_widget -> widget -> dobj .private ;
414+ sink_widget = sroute -> sink_widget -> widget -> dobj .private ;
388415
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- }
416+ /*
417+ * it is enough to check if the direction_valid is set for one of the
418+ * widgets as all widgets will have the direction set in topology if one
419+ * is set.
420+ */
421+ if (src_widget && sink_widget &&
422+ src_widget -> spipe -> direction_valid &&
423+ sof_widget_in_same_direction (sink_widget , src_widget -> spipe -> direction ))
424+ continue ;
399425 }
400426
427+ ret = sof_route_setup (sdev , sroute -> src_widget -> widget ,
428+ sroute -> sink_widget -> widget );
429+
401430 if (ret < 0 )
402431 return ret ;
403432 }
404433
405434 return 0 ;
406435}
407436
437+
438+
408439static void
409440sof_unprepare_widgets_in_path (struct snd_sof_dev * sdev , struct snd_soc_dapm_widget * widget ,
410- struct snd_soc_dapm_widget_list * list )
441+ struct snd_soc_dapm_widget_list * list , int dir )
411442{
412443 const struct sof_ipc_tplg_ops * tplg_ops = sof_ipc_get_ops (sdev , tplg );
413444 struct snd_sof_widget * swidget = widget -> dobj .private ;
414445 const struct sof_ipc_tplg_widget_ops * widget_ops ;
415446 struct snd_soc_dapm_path * p ;
416447
417- /* skip if the widget in use or already unprepared or virtual widgets */
418- if (!swidget || !swidget -> prepared || swidget -> use_count > 0 ||
419- is_virtual_widget (sdev , widget , __func__ ))
448+ /* skip vritual widgets */
449+ if (!swidget || is_virtual_widget (sdev , widget , __func__ ))
420450 goto sink_unprepare ;
421451
422- /* skip aggregated DAIs */
423- if (is_aggregated_dai (swidget ))
452+ if (swidget -> spipe -> direction_valid && !sof_widget_in_same_direction (swidget , dir ))
453+ return ;
454+
455+ /* skip widgets in use, those already unprepared or aggregated DAIs */
456+ if (!swidget -> prepared || swidget -> use_count > 0 || is_aggregated_dai (swidget ))
424457 goto sink_unprepare ;
425458
426459 widget_ops = tplg_ops ? tplg_ops -> widget : NULL ;
@@ -435,9 +468,10 @@ sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widg
435468 snd_soc_dapm_widget_for_each_sink_path (widget , p ) {
436469 if (!widget_in_list (list , p -> sink ))
437470 continue ;
471+
438472 if (!p -> walking && p -> sink -> dobj .private ) {
439473 p -> walking = true;
440- sof_unprepare_widgets_in_path (sdev , p -> sink , list );
474+ sof_unprepare_widgets_in_path (sdev , p -> sink , list , dir );
441475 p -> walking = false;
442476 }
443477 }
@@ -456,18 +490,19 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget
456490 struct snd_soc_dapm_path * p ;
457491 int ret ;
458492
459- if (is_virtual_widget (sdev , widget , __func__ ))
493+ if (is_virtual_widget (sdev , widget , __func__ ) || ! swidget )
460494 goto sink_prepare ;
461495
462496 widget_ops = tplg_ops ? tplg_ops -> widget : NULL ;
463497 if (!widget_ops )
464498 return 0 ;
465499
466- if (! swidget || ! widget_ops [ widget -> id ]. ipc_prepare || swidget -> prepared )
467- goto sink_prepare ;
500+ if (swidget -> spipe -> direction_valid && ! sof_widget_in_same_direction ( swidget , dir ) )
501+ return 0 ;
468502
469- /* skip aggregated DAIs */
470- if (is_aggregated_dai (swidget ))
503+ /* skip widgets already prepared or aggregated DAI widgets*/
504+ if (!widget_ops [widget -> id ].ipc_prepare || swidget -> prepared ||
505+ is_aggregated_dai (swidget ))
471506 goto sink_prepare ;
472507
473508 /* prepare the source widget */
@@ -485,6 +520,7 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget
485520 snd_soc_dapm_widget_for_each_sink_path (widget , p ) {
486521 if (!widget_in_list (list , p -> sink ))
487522 continue ;
523+
488524 if (!p -> walking && p -> sink -> dobj .private ) {
489525 p -> walking = true;
490526 ret = sof_prepare_widgets_in_path (sdev , p -> sink , fe_params ,
@@ -514,23 +550,25 @@ static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dap
514550 int dir , struct snd_sof_pcm * spcm )
515551{
516552 struct snd_soc_dapm_widget_list * list = spcm -> stream [dir ].list ;
517- struct snd_sof_widget * swidget ;
553+ struct snd_sof_widget * swidget = widget -> dobj . private ;
518554 struct snd_soc_dapm_path * p ;
519555 int err ;
520556 int ret = 0 ;
521557
522- if (is_virtual_widget (sdev , widget , __func__ ))
558+ if (is_virtual_widget (sdev , widget , __func__ ) || ! swidget )
523559 goto sink_free ;
524560
525- swidget = widget -> dobj .private ;
561+ if (swidget -> spipe -> direction_valid && !sof_widget_in_same_direction (swidget , dir ))
562+ return 0 ;
526563
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- }
564+ /* skip aggregated DAIs */
565+ if (is_aggregated_dai (swidget ))
566+ goto sink_free ;
533567
568+ err = sof_widget_free (sdev , widget -> dobj .private );
569+ if (err < 0 )
570+ ret = err ;
571+ sink_free :
534572 /* free all widgets in the sink paths even in case of error to keep use counts balanced */
535573 snd_soc_dapm_widget_for_each_sink_path (widget , p ) {
536574 if (!p -> walking ) {
@@ -570,6 +608,10 @@ static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_d
570608 if (swidget ) {
571609 int i ;
572610
611+ if (swidget -> spipe -> direction_valid && !sof_widget_in_same_direction (swidget , dir ))
612+ return 0 ;
613+
614+ /* skip aggregated DAIs */
573615 if (is_aggregated_dai (swidget ))
574616 goto sink_setup ;
575617
@@ -635,15 +677,14 @@ sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
635677 return 0 ;
636678
637679 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 )
680+ /* starting widget for playback is of AIF or snd_soc_dapm_input type */
681+ if (dir == SNDRV_PCM_STREAM_PLAYBACK && (widget -> id != snd_soc_dapm_aif_in &&
682+ widget -> id != snd_soc_dapm_input ))
643683 continue ;
644684
645685 /* starting widget for capture is DAI type */
646- if (dir == SNDRV_PCM_STREAM_CAPTURE && widget -> id != snd_soc_dapm_dai_out )
686+ if (dir == SNDRV_PCM_STREAM_CAPTURE && widget -> id != snd_soc_dapm_dai_out &&
687+ widget -> id != snd_soc_dapm_output )
647688 continue ;
648689
649690 switch (op ) {
@@ -673,7 +714,7 @@ sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
673714 break ;
674715 }
675716 case SOF_WIDGET_UNPREPARE :
676- sof_unprepare_widgets_in_path (sdev , widget , list );
717+ sof_unprepare_widgets_in_path (sdev , widget , list , dir );
677718 break ;
678719 default :
679720 dev_err (sdev -> dev , "Invalid widget op %d\n" , op );
@@ -920,29 +961,41 @@ struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp,
920961 return NULL ;
921962}
922963
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 )
964+ static struct snd_sof_widget * snd_sof_find_swidget_sname_type (struct snd_soc_component * scomp ,
965+ const char * sname ,
966+ enum snd_soc_dapm_type type )
927967{
928968 struct snd_sof_dev * sdev = snd_soc_component_get_drvdata (scomp );
929969 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 ;
936970
937971 list_for_each_entry (swidget , & sdev -> widget_list , list ) {
938- if (!strcmp (pcm_name , swidget -> widget -> sname ) &&
939- swidget -> id == type )
972+ if (!strcmp (sname , swidget -> widget -> sname ) && swidget -> id == type )
940973 return swidget ;
941974 }
942975
943976 return NULL ;
944977}
945978
979+ /* find widget by stream name and direction */
980+ struct snd_sof_widget *
981+ snd_sof_find_swidget_sname (struct snd_soc_component * scomp ,
982+ const char * pcm_name , int dir )
983+ {
984+ if (dir == SNDRV_PCM_STREAM_PLAYBACK ) {
985+ struct snd_sof_widget * swidget ;
986+
987+ /* first look for an aif_in type widget */
988+ swidget = snd_sof_find_swidget_sname_type (scomp , pcm_name , snd_soc_dapm_aif_in );
989+ if (swidget )
990+ return swidget ;
991+
992+ /* if not found, look for an input type widget */
993+ return snd_sof_find_swidget_sname_type (scomp , pcm_name , snd_soc_dapm_input );
994+ }
995+
996+ return snd_sof_find_swidget_sname_type (scomp , pcm_name , snd_soc_dapm_aif_out );
997+ }
998+
946999struct snd_sof_dai * snd_sof_find_dai (struct snd_soc_component * scomp ,
9471000 const char * name )
9481001{
0 commit comments