diff options
Diffstat (limited to 'sound/soc/soc-pcm.c')
-rw-r--r-- | sound/soc/soc-pcm.c | 462 |
1 files changed, 416 insertions, 46 deletions
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 94b88b897c3b..8075856668c2 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -133,16 +133,25 @@ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) */ bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd) { + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; int i; bool ignore = true; if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time) return true; + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + ignore &= !component->driver->pmdown_time; + } + + /* this will be removed */ for (i = 0; i < rtd->num_codecs; i++) ignore &= rtd->codec_dais[i]->component->ignore_pmdown_time; - return rtd->cpu_dai->component->ignore_pmdown_time && ignore; + return ignore; } /** @@ -459,7 +468,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; const char *codec_dai_name = "multicodec"; - int i, ret = 0; + int i, ret = 0, __ret; pinctrl_pm_select_default_state(cpu_dai->dev); for (i = 0; i < rtd->num_codecs; i++) @@ -474,7 +483,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); /* startup the audio subsystem */ - if (cpu_dai->driver->ops && cpu_dai->driver->ops->startup) { + if (cpu_dai->driver->ops->startup) { ret = cpu_dai->driver->ops->startup(substream, cpu_dai); if (ret < 0) { dev_err(cpu_dai->dev, "ASoC: can't open interface" @@ -483,7 +492,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } } - if (platform->driver->ops && platform->driver->ops->open) { + if (platform && 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" @@ -492,9 +501,32 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } } + ret = 0; + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* ignore duplication for now */ + if (platform && (component == &platform->component)) + continue; + + if (!component->driver->ops || + !component->driver->ops->open) + continue; + + __ret = component->driver->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]; - if (codec_dai->driver->ops && codec_dai->driver->ops->startup) { + if (codec_dai->driver->ops->startup) { ret = codec_dai->driver->ops->startup(substream, codec_dai); if (ret < 0) { @@ -511,7 +543,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) codec_dai->rx_mask = 0; } - if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { + if (rtd->dai_link->ops->startup) { ret = rtd->dai_link->ops->startup(substream); if (ret < 0) { pr_err("ASoC: %s startup failed: %d\n", @@ -585,7 +617,7 @@ dynamic: return 0; config_err: - if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) + if (rtd->dai_link->ops->shutdown) rtd->dai_link->ops->shutdown(substream); machine_err: @@ -598,7 +630,22 @@ codec_dai_err: codec_dai->driver->ops->shutdown(substream, codec_dai); } - if (platform->driver->ops && platform->driver->ops->close) +component_err: + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* ignore duplication for now */ + if (platform && (component == &platform->component)) + continue; + + if (!component->driver->ops || + !component->driver->ops->close) + continue; + + component->driver->ops->close(substream); + } + + if (platform && platform->driver->ops && platform->driver->ops->close) platform->driver->ops->close(substream); platform_err: @@ -692,12 +739,26 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) codec_dai->driver->ops->shutdown(substream, codec_dai); } - if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) + if (rtd->dai_link->ops->shutdown) rtd->dai_link->ops->shutdown(substream); - if (platform->driver->ops && platform->driver->ops->close) + if (platform && platform->driver->ops && platform->driver->ops->close) platform->driver->ops->close(substream); + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* ignore duplication for now */ + if (platform && (component == &platform->component)) + continue; + + if (!component->driver->ops || + !component->driver->ops->close) + continue; + + component->driver->ops->close(substream); + } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (snd_soc_runtime_ignore_pmdown_time(rtd)) { /* powered down playback stream now */ @@ -745,13 +806,15 @@ 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_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; int i, ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); - if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) { + if (rtd->dai_link->ops->prepare) { ret = rtd->dai_link->ops->prepare(substream); if (ret < 0) { dev_err(rtd->card->dev, "ASoC: machine prepare error:" @@ -760,7 +823,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } } - if (platform->driver->ops && platform->driver->ops->prepare) { + if (platform && platform->driver->ops && platform->driver->ops->prepare) { ret = platform->driver->ops->prepare(substream); if (ret < 0) { dev_err(platform->dev, "ASoC: platform prepare error:" @@ -769,9 +832,28 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } } + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* ignore duplication for now */ + if (platform && (component == &platform->component)) + continue; + + if (!component->driver->ops || + !component->driver->ops->prepare) + continue; + + ret = component->driver->ops->prepare(substream); + if (ret < 0) { + dev_err(component->dev, + "ASoC: platform prepare error: %d\n", ret); + goto out; + } + } + for (i = 0; i < rtd->num_codecs; i++) { codec_dai = rtd->codec_dais[i]; - if (codec_dai->driver->ops && codec_dai->driver->ops->prepare) { + if (codec_dai->driver->ops->prepare) { ret = codec_dai->driver->ops->prepare(substream, codec_dai); if (ret < 0) { @@ -783,7 +865,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } } - if (cpu_dai->driver->ops && cpu_dai->driver->ops->prepare) { + if (cpu_dai->driver->ops->prepare) { ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); if (ret < 0) { dev_err(cpu_dai->dev, @@ -829,7 +911,7 @@ int soc_dai_hw_params(struct snd_pcm_substream *substream, { int ret; - if (dai->driver->ops && dai->driver->ops->hw_params) { + if (dai->driver->ops->hw_params) { ret = dai->driver->ops->hw_params(substream, params, dai); if (ret < 0) { dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n", @@ -851,16 +933,13 @@ static int soc_pcm_hw_params(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_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int i, ret = 0; + int i, ret = 0, __ret; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); - - ret = soc_pcm_params_symmetry(substream, params); - if (ret) - goto out; - - if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { + if (rtd->dai_link->ops->hw_params) { ret = rtd->dai_link->ops->hw_params(substream, params); if (ret < 0) { dev_err(rtd->card->dev, "ASoC: machine hw_params" @@ -915,7 +994,7 @@ 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) { + if (platform && 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", @@ -924,18 +1003,62 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } } + ret = 0; + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* ignore duplication for now */ + if (platform && (component == &platform->component)) + continue; + + if (!component->driver->ops || + !component->driver->ops->hw_params) + continue; + + __ret = component->driver->ops->hw_params(substream, params); + if (__ret < 0) { + dev_err(component->dev, + "ASoC: %s hw params failed: %d\n", + component->name, ret); + ret = __ret; + } + } + if (ret < 0) + goto component_err; + /* store the parameters for each DAIs */ cpu_dai->rate = params_rate(params); cpu_dai->channels = params_channels(params); cpu_dai->sample_bits = snd_pcm_format_physical_width(params_format(params)); + ret = soc_pcm_params_symmetry(substream, params); + if (ret) + goto component_err; out: mutex_unlock(&rtd->pcm_mutex); return ret; +component_err: + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* ignore duplication */ + if (platform && (component == &platform->component)) + continue; + + if (!component->driver->ops || + !component->driver->ops->hw_free) + continue; + + component->driver->ops->hw_free(substream); + } + + if (platform && platform->driver->ops && platform->driver->ops->hw_free) + platform->driver->ops->hw_free(substream); + platform_err: - if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free) + if (cpu_dai->driver->ops->hw_free) cpu_dai->driver->ops->hw_free(substream, cpu_dai); interface_err: @@ -944,12 +1067,12 @@ interface_err: codec_err: while (--i >= 0) { struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; - if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free) + if (codec_dai->driver->ops->hw_free) codec_dai->driver->ops->hw_free(substream, codec_dai); codec_dai->rate = 0; } - if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) + if (rtd->dai_link->ops->hw_free) rtd->dai_link->ops->hw_free(substream); mutex_unlock(&rtd->pcm_mutex); @@ -963,6 +1086,8 @@ 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_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; @@ -995,21 +1120,36 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) } /* free any machine hw params */ - if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) + if (rtd->dai_link->ops->hw_free) rtd->dai_link->ops->hw_free(substream); /* free any DMA resources */ - if (platform->driver->ops && platform->driver->ops->hw_free) + if (platform && platform->driver->ops && platform->driver->ops->hw_free) platform->driver->ops->hw_free(substream); + /* free any component resources */ + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* ignore duplication for now */ + if (platform && (component == &platform->component)) + continue; + + if (!component->driver->ops || + !component->driver->ops->hw_free) + continue; + + component->driver->ops->hw_free(substream); + } + /* now free hw params for the DAIs */ for (i = 0; i < rtd->num_codecs; i++) { codec_dai = rtd->codec_dais[i]; - if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free) + if (codec_dai->driver->ops->hw_free) codec_dai->driver->ops->hw_free(substream, codec_dai); } - if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free) + if (cpu_dai->driver->ops->hw_free) cpu_dai->driver->ops->hw_free(substream, cpu_dai); mutex_unlock(&rtd->pcm_mutex); @@ -1020,13 +1160,15 @@ 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_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; int i, ret; for (i = 0; i < rtd->num_codecs; i++) { codec_dai = rtd->codec_dais[i]; - if (codec_dai->driver->ops && codec_dai->driver->ops->trigger) { + if (codec_dai->driver->ops->trigger) { ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai); if (ret < 0) @@ -1034,19 +1176,35 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) } } - if (platform->driver->ops && platform->driver->ops->trigger) { + if (platform && platform->driver->ops && platform->driver->ops->trigger) { ret = platform->driver->ops->trigger(substream, cmd); if (ret < 0) return ret; } - if (cpu_dai->driver->ops && cpu_dai->driver->ops->trigger) { + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* ignore duplication for now */ + if (platform && (component == &platform->component)) + continue; + + if (!component->driver->ops || + !component->driver->ops->trigger) + continue; + + ret = component->driver->ops->trigger(substream, cmd); + if (ret < 0) + return ret; + } + + if (cpu_dai->driver->ops->trigger) { ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai); if (ret < 0) return ret; } - if (rtd->dai_link->ops && rtd->dai_link->ops->trigger) { + if (rtd->dai_link->ops->trigger) { ret = rtd->dai_link->ops->trigger(substream, cmd); if (ret < 0) return ret; @@ -1065,8 +1223,7 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, for (i = 0; i < rtd->num_codecs; i++) { codec_dai = rtd->codec_dais[i]; - if (codec_dai->driver->ops && - codec_dai->driver->ops->bespoke_trigger) { + if (codec_dai->driver->ops->bespoke_trigger) { ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai); if (ret < 0) @@ -1074,7 +1231,7 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, } } - if (cpu_dai->driver->ops && cpu_dai->driver->ops->bespoke_trigger) { + if (cpu_dai->driver->ops->bespoke_trigger) { ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai); if (ret < 0) return ret; @@ -1090,6 +1247,8 @@ 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_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; struct snd_pcm_runtime *runtime = substream->runtime; @@ -1098,15 +1257,31 @@ 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) + if (platform && platform->driver->ops && platform->driver->ops->pointer) offset = platform->driver->ops->pointer(substream); - if (cpu_dai->driver->ops && cpu_dai->driver->ops->delay) + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* ignore duplication for now */ + if (platform && (component == &platform->component)) + continue; + + if (!component->driver->ops || + !component->driver->ops->pointer) + continue; + + /* FIXME: use 1st pointer */ + offset = component->driver->ops->pointer(substream); + break; + } + + if (cpu_dai->driver->ops->delay) delay += cpu_dai->driver->ops->delay(substream, cpu_dai); for (i = 0; i < rtd->num_codecs; i++) { codec_dai = rtd->codec_dais[i]; - if (codec_dai->driver->ops && codec_dai->driver->ops->delay) + if (codec_dai->driver->ops->delay) codec_delay = max(codec_delay, codec_dai->driver->ops->delay(substream, codec_dai)); @@ -2285,9 +2460,27 @@ static int soc_pcm_ioctl(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_rtdcom_list *rtdcom; - if (platform->driver->ops && platform->driver->ops->ioctl) + if (platform && platform->driver->ops && platform->driver->ops->ioctl) return platform->driver->ops->ioctl(substream, cmd, arg); + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + /* ignore duplication for now */ + if (platform && (component == &platform->component)) + continue; + + if (!component->driver->ops || + !component->driver->ops->ioctl) + continue; + + /* FIXME: use 1st ioctl */ + return component->driver->ops->ioctl(substream, cmd, arg); + } + return snd_pcm_lib_ioctl(substream, cmd, arg); } @@ -2632,12 +2825,163 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) return ret; } +static void soc_pcm_private_free(struct snd_pcm *pcm) +{ + struct snd_soc_pcm_runtime *rtd = pcm->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + + for_each_rtdcom(rtd, rtdcom) { + /* need to sync the delayed work before releasing resources */ + + flush_delayed_work(&rtd->delayed_work); + component = rtdcom->component; + + if (component->pcm_free) + component->pcm_free(component, pcm); + } +} + +static int soc_rtdcom_ack(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (!component->driver->ops || + !component->driver->ops->ack) + continue; + + /* FIXME. it returns 1st ask now */ + return component->driver->ops->ack(substream); + } + + return -EINVAL; +} + +static int soc_rtdcom_copy_user(struct snd_pcm_substream *substream, int channel, + unsigned long pos, void __user *buf, + unsigned long bytes) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (!component->driver->ops || + !component->driver->ops->copy_user) + continue; + + /* FIXME. it returns 1st copy now */ + return component->driver->ops->copy_user(substream, channel, + pos, buf, bytes); + } + + return -EINVAL; +} + +static int soc_rtdcom_copy_kernel(struct snd_pcm_substream *substream, int channel, + unsigned long pos, void *buf, unsigned long bytes) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (!component->driver->ops || + !component->driver->ops->copy_kernel) + continue; + + /* FIXME. it returns 1st copy now */ + return component->driver->ops->copy_kernel(substream, channel, + pos, buf, bytes); + } + + return -EINVAL; +} + +static int soc_rtdcom_fill_silence(struct snd_pcm_substream *substream, int channel, + unsigned long pos, unsigned long bytes) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (!component->driver->ops || + !component->driver->ops->fill_silence) + continue; + + /* FIXME. it returns 1st silence now */ + return component->driver->ops->fill_silence(substream, channel, + pos, bytes); + } + + return -EINVAL; +} + +static struct page *soc_rtdcom_page(struct snd_pcm_substream *substream, + unsigned long offset) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + struct page *page; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (!component->driver->ops || + !component->driver->ops->page) + continue; + + /* FIXME. it returns 1st page now */ + page = component->driver->ops->page(substream, offset); + if (page) + return page; + } + + return NULL; +} + +static int soc_rtdcom_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_rtdcom_list *rtdcom; + struct snd_soc_component *component; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (!component->driver->ops || + !component->driver->ops->mmap) + continue; + + /* FIXME. it returns 1st mmap now */ + return component->driver->ops->mmap(substream, vma); + } + + return -EINVAL; +} + /* 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; + struct snd_soc_rtdcom_list *rtdcom; struct snd_pcm *pcm; char new_name[64]; int ret = 0, playback = 0, capture = 0; @@ -2732,7 +3076,28 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) rtd->ops.ioctl = soc_pcm_ioctl; } - if (platform->driver->ops) { + for_each_rtdcom(rtd, rtdcom) { + const struct snd_pcm_ops *ops = rtdcom->component->driver->ops; + + if (!ops) + continue; + + if (ops->ack) + rtd->ops.ack = soc_rtdcom_ack; + if (ops->copy_user) + rtd->ops.copy_user = soc_rtdcom_copy_user; + if (ops->copy_kernel) + rtd->ops.copy_kernel = soc_rtdcom_copy_kernel; + if (ops->fill_silence) + rtd->ops.fill_silence = soc_rtdcom_fill_silence; + if (ops->page) + rtd->ops.page = soc_rtdcom_page; + if (ops->mmap) + rtd->ops.mmap = soc_rtdcom_mmap; + } + + /* overwrite */ + if (platform && platform->driver->ops) { rtd->ops.ack = platform->driver->ops->ack; rtd->ops.copy_user = platform->driver->ops->copy_user; rtd->ops.copy_kernel = platform->driver->ops->copy_kernel; @@ -2747,17 +3112,22 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) if (capture) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops); - if (platform->driver->pcm_new) { - ret = platform->driver->pcm_new(rtd); + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (!component->pcm_new) + continue; + + ret = component->pcm_new(component, rtd); if (ret < 0) { - dev_err(platform->dev, + dev_err(component->dev, "ASoC: pcm constructor failed: %d\n", ret); return ret; } } - pcm->private_free = platform->driver->pcm_free; + pcm->private_free = soc_pcm_private_free; out: dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name, |