[alsa-devel] [PATCH 1/4] sound: soc: msm7k: add mmap interface
Denis 'GNUtoo' Carikli
GNUtoo at no-log.org
Sun Aug 15 20:08:10 CEST 2010
The mmap interface is a patch rebased from this msm7kv2 alsa driver patch:
commit c25698fee4fbd82a325394263752cb8b843fcfdc
Author: Asish Bhattacharya <asishb at qualcomm.com>
Date: Thu Jan 21 14:38:41 2010 +0530
alsa: soc: MMAP capability to playback stream
The current code supports playback non-mmap(copy) mode playback.
Adding support to do mmap-mode playback.
Signed-off-by: Asish Bhattacharya <asishb at qualcomm.com>
It is comming from git://codeaurora.org/kernel/msm.git
Note that this is still not usable,because the buffer underrun
are a lot worse than with non-mmaped interface.
Signed-off-by: Denis 'GNUtoo' Carikli <GNUtoo at no-log.org>
---
sound/soc/msm/TODO | 4 ++
sound/soc/msm/msm-pcm.c | 8 ++-
sound/soc/msm/msm-pcm.h | 7 ++-
sound/soc/msm/msm7k-pcm.c | 110 ++++++++++++++++++++++++++++++++++++++++++---
4 files changed, 117 insertions(+), 12 deletions(-)
create mode 100644 sound/soc/msm/TODO
diff --git a/sound/soc/msm/TODO b/sound/soc/msm/TODO
new file mode 100644
index 0000000..87084ea
--- /dev/null
+++ b/sound/soc/msm/TODO
@@ -0,0 +1,4 @@
+ad4974853c00ac1b6ac388a2915d86c06a04447f
+87a86ea6bd2868d9e9b3113f366e7ca440ef6199
+35240ee6cc224db5c916b345ae7a23fbe9b1ade6
+3d02aeb5607c558dec70054a234b2f36007ea362
diff --git a/sound/soc/msm/msm-pcm.c b/sound/soc/msm/msm-pcm.c
index f90c778..23c2c55 100644
--- a/sound/soc/msm/msm-pcm.c
+++ b/sound/soc/msm/msm-pcm.c
@@ -47,8 +47,6 @@
msm_adsp_write(prtd->audrec, QDSP_uPAudRecCmdQueue, cmd, len)
int intcnt;
-static int audio_dsp_send_buffer(struct msm_audio *prtd,
- unsigned idx, unsigned len);
struct audio_frame {
uint16_t count_low;
@@ -141,6 +139,9 @@ void alsa_dsp_event(void *data, unsigned id, uint16_t *msg)
if (prtd->ops->playback)
prtd->ops->playback(prtd);
+ if (prtd->mmap_flag)
+ break;
+
spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
if (prtd->running) {
prtd->out[idx].used = 0;
@@ -631,7 +632,7 @@ int alsa_buffer_read(struct msm_audio *prtd, void __user *buf,
}
EXPORT_SYMBOL(alsa_buffer_read);
-static int audio_dsp_send_buffer(struct msm_audio *prtd,
+int audio_dsp_send_buffer(struct msm_audio *prtd,
unsigned idx, unsigned len)
{
audpp_cmd_pcm_intf_send_buffer cmd;
@@ -645,6 +646,7 @@ static int audio_dsp_send_buffer(struct msm_audio *prtd,
return audpp_send_queue2(&cmd, sizeof(cmd));
}
+
int alsa_rec_dsp_enable(struct msm_audio *prtd, int enable)
{
audrec_cmd_cfg cmd;
diff --git a/sound/soc/msm/msm-pcm.h b/sound/soc/msm/msm-pcm.h
index 9551bb0..62651a7 100644
--- a/sound/soc/msm/msm-pcm.h
+++ b/sound/soc/msm/msm-pcm.h
@@ -52,8 +52,7 @@
(SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
#define USE_RATE_MIN 8000
#define USE_RATE_MAX 48000
-#define MAX_BUFFER_PLAYBACK_SIZE \
- (4800*4)
+#define MAX_BUFFER_PLAYBACK_SIZE PLAYBACK_DMASZ
/* 2048 frames (Mono), 1024 frames (Stereo) */
#define CAPTURE_SIZE 4096
#define MAX_BUFFER_CAPTURE_SIZE (4096*4)
@@ -174,6 +173,8 @@ struct msm_audio {
int running;
int stopped; /* set when stopped, cleared on flush */
int eos_ack;
+ int mmap_flag;
+ int period;
};
@@ -193,6 +194,8 @@ extern int alsa_audio_disable(struct msm_audio *prtd);
extern int alsa_adsp_configure(struct msm_audio *prtd);
extern int alsa_buffer_read(struct msm_audio *prtd, void __user *buf,
size_t count, loff_t *pos);
+extern int audio_dsp_send_buffer(struct msm_audio *prtd,
+ unsigned idx, unsigned len);
ssize_t alsa_send_buffer(struct msm_audio *prtd, const char __user *buf,
size_t count, loff_t *pos, int copy_count);
int msm_audio_volume_update(unsigned id,
diff --git a/sound/soc/msm/msm7k-pcm.c b/sound/soc/msm/msm7k-pcm.c
index c366902..9561e91 100644
--- a/sound/soc/msm/msm7k-pcm.c
+++ b/sound/soc/msm/msm7k-pcm.c
@@ -108,7 +108,9 @@ static unsigned convert_samp_rate(unsigned hz)
}
static struct snd_pcm_hardware msm_pcm_playback_hardware = {
- .info = SNDRV_PCM_INFO_INTERLEAVED,
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED,
.formats = USE_FORMATS,
.rates = USE_RATE,
.rate_min = USE_RATE_MIN,
@@ -150,10 +152,35 @@ static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
.mask = 0,
};
+static void msm_pcm_enqueue_data(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+ unsigned int period_size;
+
+ period_size = snd_pcm_lib_period_bytes(substream);
+ audio_dsp_send_buffer(prtd, prtd->out_tail, period_size);
+ prtd->out_tail ^= 1;
+ ++copy_count;
+ prtd->period++;
+ if (unlikely(prtd->period >= runtime->periods))
+ prtd->period = 0;
+
+}
+
+
static void playback_event_handler(void *data)
{
struct msm_audio *prtd = data;
snd_pcm_period_elapsed(prtd->playback_substream);
+ if (prtd->mmap_flag) {
+ if (prtd->dir == SNDRV_PCM_STREAM_CAPTURE)
+ return;
+ if (!prtd->stopped)
+ msm_pcm_enqueue_data(prtd->playback_substream);
+ else
+ prtd->out_needed++;
+ }
}
static void capture_event_handler(void *data)
@@ -171,10 +198,30 @@ static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
prtd->pcm_irq_pos = 0;
prtd->pcm_buf_pos = 0;
+ if (prtd->enabled)
+ return 0;
/* rate and channels are sent to audio driver */
prtd->out_sample_rate = runtime->rate;
prtd->out_channel_mode = runtime->channels;
+ /* prtd->data = prtd->substream->dma_buffer.area; */
+ /* prtd->phys = prtd->substream->dma_buffer.addr; */
+ /* prtd->out[0].data = prtd->data + 0; */
+ /* prtd->out[0].addr = prtd->phys + 0; */
+ /* prtd->out[0].size = BUFSZ; */
+ /* prtd->out[1].data = prtd->data + BUFSZ; */
+ /* prtd->out[1].addr = prtd->phys + BUFSZ; */
+ /* prtd->out[1].size = BUFSZ; */
+
+ if (prtd->enabled | !(prtd->mmap_flag))
+ return 0;
+
+ prtd->out[0].used = prtd->pcm_count;
+ prtd->out[1].used = prtd->pcm_count;
+
+ mutex_lock(&the_locks.lock);
+ alsa_audio_configure(prtd);
+ mutex_unlock(&the_locks.lock);
return 0;
}
@@ -230,19 +277,56 @@ static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+ unsigned long flag = 0;
int ret = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ || !prtd->mmap_flag)
+ break;
+ if (!prtd->out_needed) {
+ prtd->stopped = 0;
+ break;
+ }
+ spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
+ if (prtd->running == 1) {
+ if (prtd->stopped == 1) {
+ prtd->stopped = 0;
+ prtd->period = 0;
+ if (prtd->pcm_irq_pos == 0) {
+ prtd->out_tail = 0;
+ msm_pcm_enqueue_data(prtd->playback_substream);
+ prtd->out_needed--;
+ } else {
+ prtd->out_tail = 1;
+ msm_pcm_enqueue_data(prtd->playback_substream);
+ prtd->out_needed--;
+ }
+ if (prtd->out_needed) {
+ prtd->out_tail ^= 1;
+ msm_pcm_enqueue_data(prtd->playback_substream);
+ prtd->out_needed--;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ || !prtd->mmap_flag)
+ break;
+ prtd->stopped = 1;
break;
default:
ret = -EINVAL;
+ break;
}
return ret;
@@ -463,16 +547,27 @@ static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
int msm_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- if (substream->pcm->device & 1) {
- runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
- runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
- }
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
return 0;
}
+int msm_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+ {
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct msm_audio *prtd = runtime->private_data;
+
+ prtd->out_head = 0; /* point to First buffer on startup */
+ prtd->mmap_flag = 1;
+ runtime->dma_bytes = snd_pcm_lib_period_bytes(substream)*2;
+ dma_mmap_coherent(substream->pcm->card->dev, vma,
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
+ return 0;
+}
+
static struct snd_pcm_ops msm_pcm_ops = {
.open = msm_pcm_open,
.copy = msm_pcm_copy,
@@ -483,6 +578,7 @@ static struct snd_pcm_ops msm_pcm_ops = {
.prepare = msm_pcm_prepare,
.trigger = msm_pcm_trigger,
.pointer = msm_pcm_pointer,
+ .mmap = msm_pcm_mmap,
};
--
1.7.0.4
More information about the Alsa-devel
mailing list