diff mbox

[RFC,1/x] ASoC: snd_soc_component_driver has snd_pcm_ops

Message ID 87vamh5f1p.wl%kuninori.morimoto.gx@renesas.com (mailing list archive)
State New, archived
Headers show

Commit Message

Kuninori Morimoto July 25, 2017, 4:20 a.m. UTC
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>

snd_soc_platform_driver has snd_pcm_ops,
and it will be replaced into snd_soc_component_driver in the future.
To prepare it, this patch adds ops on component driver.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 include/sound/soc.h |   2 +
 sound/soc/soc-pcm.c | 364 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 354 insertions(+), 12 deletions(-)
diff mbox

Patch

diff --git a/include/sound/soc.h b/include/sound/soc.h
index ff5773d..3952075 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -820,6 +820,8 @@  struct snd_soc_component_driver {
 		int subseq);
 	int (*stream_event)(struct snd_soc_component *, int event);
 
+	const struct snd_pcm_ops *ops;
+
 	/* probe ordering - for components with runtime dependencies */
 	int probe_order;
 	int remove_order;
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 844bbd5..e1c3d5c7 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -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 && codec_dai->driver->ops->startup) {
@@ -598,7 +621,22 @@  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)
+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 && 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 && 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);
 
@@ -915,7 +990,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,6 +999,29 @@  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);
@@ -934,6 +1032,24 @@  static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 	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)
 		cpu_dai->driver->ops->hw_free(substream, cpu_dai);
@@ -963,6 +1079,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;
@@ -999,9 +1117,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];
@@ -1020,6 +1153,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;
@@ -1034,12 +1169,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 && cpu_dai->driver->ops->trigger) {
 		ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
 		if (ret < 0)
@@ -1090,6 +1241,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,9 +1251,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 && cpu_dai->driver->ops->delay)
 		delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
 
@@ -2285,9 +2454,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);
 }
 
@@ -2646,6 +2833,138 @@  static void soc_pcm_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)
 {
@@ -2748,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;