From: Kuninori Morimoto kuninori.morimoto.gx@renesas.com
In current ALSA SoC, Platform has struct snd_pcm_ops feature, but it should be supported on Component level. This patch adds it.
If component level has it, many snd_pcm_ops can be called, but, 1st ops function only will be used now. It should/will be fixed in the future.
Signed-off-by: Kuninori Morimoto kuninori.morimoto.gx@renesas.com --- include/sound/soc.h | 2 + sound/soc/soc-core.c | 2 + sound/soc/soc-pcm.c | 235 ++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 192 insertions(+), 47 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index 225e9b6..f3a3601 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -777,6 +777,7 @@ struct snd_soc_component_driver { const struct snd_soc_dapm_route *dapm_routes; unsigned int num_dapm_routes;
+ const struct snd_pcm_ops *ops; const struct snd_compr_ops *compr_ops;
int (*probe)(struct snd_soc_component *); @@ -857,6 +858,7 @@ struct snd_soc_component { unsigned int num_dapm_routes; struct snd_soc_codec *codec;
+ const struct snd_pcm_ops *ops; const struct snd_compr_ops *compr_ops;
int (*probe)(struct snd_soc_component *); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ecadebe..ffa51ab 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3202,6 +3202,8 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, platform->component.pcm_free = snd_soc_platform_drv_pcm_free; if (platform_drv->compr_ops) platform->component.compr_ops = platform_drv->compr_ops; + if (platform_drv->ops) + platform->component.ops = platform_drv->ops;
#ifdef CONFIG_DEBUG_FS platform->component.debugfs_prefix = "platform"; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index ff31bf5..82a3c73 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -450,6 +450,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_component *component; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; const char *codec_dai_name = "multicodec"; @@ -475,14 +476,22 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } }
- if (platform->driver->ops && platform->driver->ops->open) { - ret = platform->driver->ops->open(substream); - if (ret < 0) { - dev_err(platform->dev, "ASoC: can't open platform" - " %s: %d\n", platform->component.name, ret); - goto platform_err; + ret = 0; + for_each_component(component, rtd->card) { + const struct snd_pcm_ops *ops = component->ops; + + if (ops && ops->open) { + int _ret = ops->open(substream); + + if (_ret < 0) + dev_err(component->dev, + "ASoC: can't open component %s: %d\n", + component->name, ret); + ret |= _ret; } } + if (ret < 0) + goto component_err;
for (i = 0; i < rtd->num_codecs; i++) { codec_dai = rtd->codec_dais[i]; @@ -590,10 +599,14 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) codec_dai->driver->ops->shutdown(substream, codec_dai); }
- if (platform->driver->ops && platform->driver->ops->close) - platform->driver->ops->close(substream); +component_err: + for_each_component(component, rtd->card) { + const struct snd_pcm_ops *ops = component->ops; + + if (ops && ops->close) + ops->close(substream); + }
-platform_err: if (cpu_dai->driver->ops->shutdown) cpu_dai->driver->ops->shutdown(substream, cpu_dai); out: @@ -655,6 +668,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_component *component; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; int i; @@ -687,8 +701,12 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) rtd->dai_link->ops->shutdown(substream);
- if (platform->driver->ops && platform->driver->ops->close) - platform->driver->ops->close(substream); + for_each_component(component, rtd->card) { + const struct snd_pcm_ops *ops = component->ops; + + if (ops && ops->close) + ops->close(substream); + }
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (snd_soc_runtime_ignore_pmdown_time(rtd)) { @@ -740,7 +758,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) static int soc_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_component *component; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; int i, ret = 0; @@ -756,12 +774,17 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } }
- if (platform->driver->ops && platform->driver->ops->prepare) { - ret = platform->driver->ops->prepare(substream); - if (ret < 0) { - dev_err(platform->dev, "ASoC: platform prepare error:" - " %d\n", ret); - goto out; + for_each_component(component, rtd->card) { + const struct snd_pcm_ops *ops = component->ops; + + if (ops && ops->prepare) { + ret = ops->prepare(substream); + if (ret < 0) { + dev_err(component->dev, + "ASoC: component prepare error: %d\n", + ret); + goto out; + } } }
@@ -846,7 +869,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_component *component; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int i, ret = 0;
@@ -911,12 +934,16 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (ret < 0) goto interface_err;
- if (platform->driver->ops && platform->driver->ops->hw_params) { - ret = platform->driver->ops->hw_params(substream, params); - if (ret < 0) { - dev_err(platform->dev, "ASoC: %s hw params failed: %d\n", - platform->component.name, ret); - goto platform_err; + for_each_component(component, rtd->card) { + const struct snd_pcm_ops *ops = component->ops; + + if (ops && ops->hw_params) { + ret = ops->hw_params(substream, params); + if (ret < 0) { + dev_err(component->dev, "ASoC: %s hw params failed: %d\n", + component->name, ret); + goto component_err; + } } }
@@ -930,7 +957,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, mutex_unlock(&rtd->pcm_mutex); return ret;
-platform_err: +component_err: if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free) cpu_dai->driver->ops->hw_free(substream, cpu_dai);
@@ -958,7 +985,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, static int soc_pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_component *component; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; @@ -995,8 +1022,12 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) rtd->dai_link->ops->hw_free(substream);
/* free any DMA resources */ - if (platform->driver->ops && platform->driver->ops->hw_free) - platform->driver->ops->hw_free(substream); + for_each_component(component, rtd->card) { + const struct snd_pcm_ops *ops = component->ops; + + if (ops && ops->hw_free) + ops->hw_free(substream); + }
/* now free hw params for the DAIs */ for (i = 0; i < rtd->num_codecs; i++) { @@ -1015,7 +1046,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_component *component; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; int i, ret; @@ -1030,10 +1061,14 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) } }
- if (platform->driver->ops && platform->driver->ops->trigger) { - ret = platform->driver->ops->trigger(substream, cmd); - if (ret < 0) - return ret; + for_each_component(component, rtd->card) { + const struct snd_pcm_ops *ops = component->ops; + + if (ops && ops->trigger) { + ret = ops->trigger(substream, cmd); + if (ret < 0) + return ret; + } }
if (cpu_dai->driver->ops && cpu_dai->driver->ops->trigger) { @@ -1085,7 +1120,7 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_component *component; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; struct snd_pcm_runtime *runtime = substream->runtime; @@ -1094,8 +1129,15 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) snd_pcm_sframes_t codec_delay = 0; int i;
- if (platform->driver->ops && platform->driver->ops->pointer) - offset = platform->driver->ops->pointer(substream); + for_each_component(component, rtd->card) { + const struct snd_pcm_ops *ops = component->ops; + + /* FIXME: It uses 1st function only now */ + if (ops && ops->pointer) { + offset = ops->pointer(substream); + break; + } + }
if (cpu_dai->driver->ops && cpu_dai->driver->ops->delay) delay += cpu_dai->driver->ops->delay(substream, cpu_dai); @@ -2278,10 +2320,16 @@ static int soc_pcm_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_component *component; + + for_each_component(component, rtd->card) { + const struct snd_pcm_ops *ops = component->ops; + + /* FIXME: It uses 1st function only now */ + if (ops && ops->ioctl) + return ops->ioctl(substream, cmd, arg); + }
- if (platform->driver->ops && platform->driver->ops->ioctl) - return platform->driver->ops->ioctl(substream, cmd, arg); return snd_pcm_lib_ioctl(substream, cmd, arg); }
@@ -2637,10 +2685,94 @@ static void soc_pcm_free(struct snd_pcm *pcm) } }
+static int soc_pcm_copy(struct snd_pcm_substream *substream, int channel, + snd_pcm_uframes_t pos, + void __user *buf, snd_pcm_uframes_t count) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component; + + for_each_component(component, rtd->card) { + const struct snd_pcm_ops *ops = component->ops; + + /* FIXME: It uses 1st function only now */ + if (ops && ops->copy) + return ops->copy(substream, channel, pos, buf, count); + } + + return -EIO; +} + +static int soc_pcm_silence(struct snd_pcm_substream *substream, int channel, + snd_pcm_uframes_t pos, snd_pcm_uframes_t count) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component; + + for_each_component(component, rtd->card) { + const struct snd_pcm_ops *ops = component->ops; + + /* FIXME: It uses 1st function only now */ + if (ops && ops->silence) + return ops->silence(substream, channel, pos, count); + } + + return -EIO; +} + +static struct page *soc_pcm_page(struct snd_pcm_substream *substream, + unsigned long offset) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component; + + for_each_component(component, rtd->card) { + const struct snd_pcm_ops *ops = component->ops; + + /* FIXME: It uses 1st function only now */ + if (ops && ops->page) + return ops->page(substream, offset); + } + + return ERR_PTR(-EIO); +} + +static int soc_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component; + + for_each_component(component, rtd->card) { + const struct snd_pcm_ops *ops = component->ops; + + /* FIXME: It uses 1st function only now */ + if (ops && ops->mmap) + return ops->mmap(substream, vma); + } + + return -EIO; +} + +static int soc_pcm_ack(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component; + + for_each_component(component, rtd->card) { + const struct snd_pcm_ops *ops = component->ops; + + /* FIXME: It uses 1st function only now */ + if (ops && ops->ack) + return ops->ack(substream); + } + + return -EIO; +} + /* create a new pcm */ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) { - struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_component *component; @@ -2738,12 +2870,21 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->ops.ioctl = soc_pcm_ioctl; }
- if (platform->driver->ops) { - rtd->ops.ack = platform->driver->ops->ack; - rtd->ops.copy = platform->driver->ops->copy; - rtd->ops.silence = platform->driver->ops->silence; - rtd->ops.page = platform->driver->ops->page; - rtd->ops.mmap = platform->driver->ops->mmap; + for_each_component(component, rtd->card) { + const struct snd_pcm_ops *ops = component->ops; + + if (ops) { + if (ops->ack) + rtd->ops.ack = soc_pcm_ack; + if (ops->copy) + rtd->ops.copy = soc_pcm_copy; + if (ops->silence) + rtd->ops.silence = soc_pcm_silence; + if (ops->page) + rtd->ops.page = soc_pcm_page; + if (ops->mmap) + rtd->ops.mmap = soc_pcm_mmap; + } }
if (playback)