[alsa-devel] [PATCH RFC 10/11] ALSA: pcm: add client_space parameter to runtime of PCM substream for PCM proxy drivers
Takashi Sakamoto
o-takashi at sakamocchi.jp
Wed May 24 02:52:54 CEST 2017
In current design of ALSA PCM core, copying PCM frames is performed between
user/kernel spaces. However, some in-kernel drivers wish to copy between
kernel/kernel spaces. I call such drivers as 'proxy' drivers.
This commit adds a infrastructure to assist the proxy drivers. New
helper functions are added to copy innner kernel space. A new member,
'client_space', is added into runtime of PCM substream to utilize these
helper functions. Usually, this member has 1 to represent target PCM frames
on user space. When this member is 0, typical copying functions are
executed between kernel/kernel space.
Reference: http://mailman.alsa-project.org/pipermail/alsa-devel/2017-May/120542.html
Signed-off-by: Takashi Sakamoto <o-takashi at sakamocchi.jp>
---
include/sound/pcm.h | 1 +
sound/core/pcm_lib.c | 147 +++++++++++++++++++++++++++++++++++++++++++-----
sound/core/pcm_native.c | 8 +++
3 files changed, 141 insertions(+), 15 deletions(-)
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index cf97e478b664..ffd21fe0b284 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -387,6 +387,7 @@ struct snd_pcm_runtime {
/* -- mmap -- */
struct snd_pcm_mmap_status *status;
struct snd_pcm_mmap_control *control;
+ int client_space; /* Where the client puts PCM frames. Usually, 1 means user space. */
/* -- locking / scheduling -- */
snd_pcm_uframes_t twake; /* do transfer (!poll) wakeup if non-zero */
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 7b8d35823de6..7700be3bb0c8 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -42,6 +42,22 @@
#define trace_hw_ptr_error(substream, reason)
#endif
+static int writei_from_space0(struct snd_pcm_substream *substream,
+ unsigned int hwoff, unsigned long data,
+ unsigned int off, snd_pcm_uframes_t count)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ char *buf = (char *)data;
+ char *dst = runtime->dma_area + frames_to_bytes(runtime, hwoff);
+
+ if (buf != NULL)
+ snd_pcm_format_set_silence(runtime->format, dst, count);
+ else
+ memcpy(dst, buf, frames_to_bytes(runtime, count));
+
+ return 0;
+}
+
static int writei_from_space1(struct snd_pcm_substream *substream,
unsigned int hwoff, unsigned long data,
unsigned int off, snd_pcm_uframes_t count)
@@ -61,6 +77,36 @@ static int writei_from_space1(struct snd_pcm_substream *substream,
return 0;
}
+static int writen_from_space0(struct snd_pcm_substream *substream,
+ unsigned int hwoff, unsigned long data,
+ unsigned int off, snd_pcm_uframes_t count)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ char **bufs = (char **)data;
+ char *buf;
+ char *dst;
+ int channels = runtime->channels;
+ snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels;
+ int c;
+
+ for (c = 0; c < channels; ++c) {
+ dst = runtime->dma_area + (c * dma_csize) +
+ samples_to_bytes(runtime, hwoff);
+
+ if (bufs == NULL || bufs[c] == NULL) {
+ snd_pcm_format_set_silence(runtime->format, dst, count);
+ continue;
+ }
+ buf = bufs[c] + samples_to_bytes(runtime, off);
+
+ dst = runtime->dma_area + (c * dma_csize) +
+ samples_to_bytes(runtime, hwoff);
+ memcpy(dst, buf, samples_to_bytes(runtime, count));
+ }
+
+ return 0;
+}
+
static int writen_from_space1(struct snd_pcm_substream *substream,
unsigned int hwoff, unsigned long data,
unsigned int off, snd_pcm_uframes_t count)
@@ -92,6 +138,19 @@ static int writen_from_space1(struct snd_pcm_substream *substream,
return 0;
}
+static int readi_to_space0(struct snd_pcm_substream *substream,
+ unsigned int hwoff, unsigned long data,
+ unsigned int off, snd_pcm_uframes_t count)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ char *buf = (char *)data + frames_to_bytes(runtime, off);
+ char *src = runtime->dma_area + frames_to_bytes(runtime, hwoff);
+
+ memcpy(buf, src, frames_to_bytes(runtime, count));
+
+ return 0;
+}
+
static int readi_to_space1(struct snd_pcm_substream *substream,
unsigned int hwoff, unsigned long data,
unsigned int off, snd_pcm_uframes_t count)
@@ -110,6 +169,31 @@ static int readi_to_space1(struct snd_pcm_substream *substream,
return 0;
}
+static int readn_to_space0(struct snd_pcm_substream *substream,
+ unsigned int hwoff, unsigned long data,
+ unsigned int off, snd_pcm_uframes_t count)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ char **bufs = (char **)data;
+ char *buf;
+ char *src;
+ unsigned int channels = runtime->channels;
+ snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels;
+ int c;
+
+ for (c = 0; c < channels; ++c) {
+ if (bufs == NULL || bufs[c] == NULL)
+ continue;
+ buf = bufs[c] + samples_to_bytes(runtime, off);
+
+ src = runtime->dma_area + (c * dma_csize) +
+ samples_to_bytes(runtime, hwoff);
+ memcpy(buf, src, samples_to_bytes(runtime, count));
+ }
+
+ return 0;
+}
+
static int readn_to_space1(struct snd_pcm_substream *substream,
unsigned int hwoff, unsigned long data,
unsigned int off, snd_pcm_uframes_t count)
@@ -203,13 +287,21 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream,
return;
if (substream->ops->copy_frames) {
+ if (runtime->client_space == 0)
+ return;
copy_frames = substream->ops->copy_frames;
} else {
if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) {
- copy_frames = writei_from_space1;
+ if (runtime->client_space == 0)
+ copy_frames = writei_from_space0;
+ else
+ copy_frames = writei_from_space1;
} else {
- copy_frames = writen_from_space1;
+ if (rnutime->client-space == 0)
+ copy_frames = writen_from_space0;
+ else
+ copy_frames = writen_from_space1;
}
}
@@ -2211,10 +2303,16 @@ snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream,
runtime->channels > 1)
return -EINVAL;
- if (substream->ops->copy_frames)
+ if (substream->ops->copy_frames) {
+ if (runtime->client_space == 0)
+ return -ENXIO;
copy_frames = substream->ops->copy_frames;
- else
- copy_frames = writei_from_space1;
+ } else {
+ if (runtime->client_space == 0)
+ copy_frames = writei_from_space0;
+ else
+ copy_frames = writei_from_space1;
+ }
return snd_pcm_lib_write1(substream, (unsigned long)buf, size, nonblock,
copy_frames);
@@ -2239,10 +2337,17 @@ snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream,
if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
return -EINVAL;
- if (substream->ops->copy_frames)
- copy_frames = substream->ops->copy_frames;
- else
- copy_frames = writen_from_space1;
+ if (substream->ops->copy_frames) {
+ if (runtime->client_space == 0)
+ return -ENXIO;
+ else
+ copy_frames = substream->ops->copy_frames;
+ } else {
+ if (runtime->client_space == 0)
+ copy_frames = writen_from_space0;
+ else
+ copy_frames = writen_from_space1;
+ }
return snd_pcm_lib_write1(substream, (unsigned long)bufs, frames,
nonblock, copy_frames);
@@ -2375,10 +2480,16 @@ snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream,
if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED)
return -EINVAL;
- if (substream->ops->copy_frames)
+ if (substream->ops->copy_frames) {
+ if (runtime->client_space == 0)
+ return -ENXIO;
copy_frames = substream->ops->copy_frames;
- else
- copy_frames = readi_to_space1;
+ } else {
+ if (runtime->client_space == 0)
+ copy_frames = readi_to_space0;
+ else
+ copy_frames = readi_to_space1;
+ }
return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock,
copy_frames);
@@ -2405,10 +2516,16 @@ snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,
if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
return -EINVAL;
- if (substream->ops->copy_frames)
+ if (substream->ops->copy_frames) {
+ if (runtime->client_space == 0)
+ return -ENXIO;
copy_frames = substream->ops->copy_frames;
- else
- copy_frames = readn_to_space1;
+ } else {
+ if (runtime->client_space == 0)
+ copy_frames = readn_to_space0;
+ else
+ copy_frames = readn_to_space1;
+ }
return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames,
nonblock, copy_frames);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index ecde57afa45a..3428583ac0d7 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -599,6 +599,14 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
if ((usecs = period_to_usecs(runtime)) >= 0)
pm_qos_add_request(&substream->latency_pm_qos_req,
PM_QOS_CPU_DMA_LATENCY, usecs);
+
+ /*
+ * Usual client puts PCM frames on user space, on the other
+ * hand PCM proxy drivers puts on kernel space. This is a
+ * switch handlers for PCM frames in different spaces.
+ */
+ runtime->client_space = 1;
+
return 0;
_error:
/* hardware might be unusable from this time,
--
2.11.0
More information about the Alsa-devel
mailing list