|
@@ -459,7 +459,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++)
|
|
@@ -483,7 +483,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,6 +492,29 @@ 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->startup) {
|
|
@@ -598,7 +621,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:
|
|
@@ -695,9 +733,23 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
|
|
|
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,6 +797,8 @@ 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;
|
|
@@ -760,7 +814,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,6 +823,25 @@ 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->prepare) {
|
|
@@ -851,8 +924,10 @@ 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);
|
|
|
if (rtd->dai_link->ops->hw_params) {
|
|
@@ -910,7 +985,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",
|
|
@@ -919,20 +994,60 @@ 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 platform_err;
|
|
|
+ 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->hw_free)
|
|
|
cpu_dai->driver->ops->hw_free(substream, cpu_dai);
|
|
@@ -962,6 +1077,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;
|
|
@@ -998,9 +1115,24 @@ 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)
|
|
|
+ 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];
|
|
@@ -1019,6 +1151,8 @@ 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;
|
|
@@ -1033,12 +1167,28 @@ 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;
|
|
|
}
|
|
|
|
|
|
+ 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)
|
|
@@ -1088,6 +1238,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;
|
|
@@ -1096,9 +1248,25 @@ 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);
|
|
|
|
|
|
+ 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);
|
|
|
|
|
@@ -2283,9 +2451,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);
|
|
|
}
|
|
|
|
|
@@ -2647,6 +2833,138 @@ static void soc_pcm_private_free(struct snd_pcm *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)
|
|
|
{
|
|
@@ -2749,7 +3067,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;
|