summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/uapi/sound/asound.h1
-rw-r--r--sound/core/pcm_native.c23
2 files changed, 22 insertions, 2 deletions
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index fd41697cb4d3..7eee52eb7462 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -268,6 +268,7 @@ typedef int __bitwise snd_pcm_subformat_t;
#define SNDRV_PCM_INFO_MMAP_VALID 0x00000002 /* period data are valid during transfer */
#define SNDRV_PCM_INFO_DOUBLE 0x00000004 /* Double buffering needed for PCM start/stop */
#define SNDRV_PCM_INFO_BATCH 0x00000010 /* double buffering */
+#define SNDRV_PCM_INFO_SYNC_APPLPTR 0x00000020 /* need the explicit sync of appl_ptr update */
#define SNDRV_PCM_INFO_INTERLEAVED 0x00000100 /* channels are interleaved */
#define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200 /* channels are not interleaved */
#define SNDRV_PCM_INFO_COMPLEX 0x00000400 /* complex frame organization (mmap only) */
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index d35c6614fdab..9ade0c8b54a3 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -3376,10 +3376,29 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file
area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
return 0;
}
+
+static bool pcm_status_mmap_allowed(struct snd_pcm_file *pcm_file)
+{
+ if (pcm_file->no_compat_mmap)
+ return false;
+ /* Disallow the status/control mmap when SYNC_APPLPTR flag is set;
+ * it enforces the user-space to fall back to snd_pcm_sync_ptr(),
+ * thus it effectively assures the manual update of appl_ptr.
+ * In theory, it should be enough to disallow only PCM control mmap,
+ * but since the current alsa-lib implementation requires both status
+ * and control mmaps always paired, we have to disable both of them.
+ */
+ if (pcm_file->substream->runtime->hw.info & SNDRV_PCM_INFO_SYNC_APPLPTR)
+ return false;
+ return true;
+}
+
#else /* ! coherent mmap */
/*
* don't support mmap for status and control records.
*/
+#define pcm_status_mmap_allowed(pcm_file) false
+
static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file,
struct vm_area_struct *area)
{
@@ -3563,11 +3582,11 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
offset = area->vm_pgoff << PAGE_SHIFT;
switch (offset) {
case SNDRV_PCM_MMAP_OFFSET_STATUS:
- if (pcm_file->no_compat_mmap)
+ if (!pcm_status_mmap_allowed(pcm_file))
return -ENXIO;
return snd_pcm_mmap_status(substream, file, area);
case SNDRV_PCM_MMAP_OFFSET_CONTROL:
- if (pcm_file->no_compat_mmap)
+ if (!pcm_status_mmap_allowed(pcm_file))
return -ENXIO;
return snd_pcm_mmap_control(substream, file, area);
default: