Skip to content
Permalink
Browse files
ASoC: SOF: sof-audio: Add helpers to set up and destroy a pipeline
Add helpers to set up and destroy a pipeline along with its widgets
and connections. Also, add a ref_count field to struct snd_sof_widget
that will be used to track the widget's usage across pipelines.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
  • Loading branch information
ranj063 committed Aug 18, 2020
1 parent 7b626b9 commit caaa61b2dbc327075d31dce1e30c5be6e9271c3e
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 0 deletions.
@@ -21,6 +21,12 @@ static int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swi
size_t ipc_size;
int ret;

/* widget set up already? */
if (swidget->ref_count)
return 0;

swidget->ref_count++;

/* skip if there is no private data */
if (!swidget->private)
return 0;
@@ -66,12 +72,84 @@ static int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swi
return ret;
}

static int sof_route_set_up(struct snd_sof_dev *sdev, struct snd_sof_widget *wsource,
struct snd_sof_widget *wsink)
{
struct sof_ipc_pipe_comp_connect connect;
struct sof_ipc_reply reply;
int ret;

connect.hdr.size = sizeof(connect);
connect.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_CONNECT;
connect.source_id = wsource->comp_id;
connect.sink_id = wsink->comp_id;

/* send ipc */
ret = sof_ipc_tx_message(sdev->ipc, connect.hdr.cmd, &connect, sizeof(connect),
&reply, sizeof(reply));
if (ret < 0)
dev_err(sdev->dev, "error: failed to load route sink %s <- %s source\n",
wsink->widget->name, wsource->widget->name);

return ret;
}

int sof_pcm_pipeline_set_up(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir)
{
struct snd_sof_route_list *route_list = spcm->stream[dir].route_list;
struct snd_sof_widget *pipeline_widget = route_list->pipeline_widget;
int ret, i;

if (!route_list)
return -ENOENT;

/* set up pipeline widget */
ret = sof_widget_setup(sdev, pipeline_widget);
if (ret < 0)
return ret;

/* set up widgets and routes as we walk the list */
for (i = 0; i < route_list->num_widgets; i++) {
struct snd_sof_widget *swidget = route_list->widgets[i];

ret = sof_widget_setup(sdev, swidget);
if (ret < 0)
return ret;

/* set up the route with the previous widget */
if (i > 0) {
struct snd_sof_widget *wsink, *wsource;

if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
wsink = swidget;
wsource = route_list->widgets[i - 1];
} else {
wsource = swidget;
wsink = route_list->widgets[i - 1];
}

ret = sof_route_set_up(sdev, wsource, wsink);
if (ret < 0)
return ret;
}
}

/* complete pipeline */
pipeline_widget->complete = snd_sof_complete_pipeline(sdev->dev, pipeline_widget);
}

static int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{
struct sof_ipc_free ipc_free;
struct sof_ipc_reply reply;
int ret;

/* free the widget only when the last pipeline it is part of has been stopped */
if (swidget->ref_count > 1)
return 0;

swidget->ref_count--;

/* skip if there is no private data */
if (!swidget->private)
return 0;
@@ -103,6 +181,30 @@ static int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swid
return ret;
}

int sof_pcm_pipeline_destroy(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir)
{
struct snd_sof_route_list *route_list = spcm->stream[dir].route_list;
struct snd_sof_widget *pipeline_widget = route_list->pipeline_widget;
int ret, i;

if (!route_list)
return -ENOENT;

/* remove pipeline widget */
ret = sof_widget_free(sdev, pipeline_widget);
if (ret < 0)
return ret;

/* remove all widgets in the route */
for (i = 0; i < route_list->num_widgets; i++) {
struct snd_sof_widget *swidget = route_list->widgets[i];

ret = sof_widget_free(sdev, swidget);
if (ret < 0)
return ret;
}
}

/*
* Free all widgets and pipelines. This should be called after topology parsing is complete
* to facilitate dynamic pipeline loading/unloading during PCM open/close.
@@ -93,6 +93,11 @@ struct snd_sof_widget {
int complete;
int core;
int id;
/*
* Widgets could be part of multiple pipeilnes. ref_count would be incremented when
* each pipeline is started
*/
int ref_count;

struct snd_soc_dapm_widget *widget;
struct list_head list; /* list in sdev widget list */
@@ -231,5 +236,7 @@ void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata);

/* PCM */
int sof_pcm_route_set_up_all(struct snd_sof_dev *sdev);
int sof_pcm_pipeline_set_up(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir);
int sof_pcm_pipeline_destroy(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir);

#endif

0 comments on commit caaa61b

Please sign in to comment.