|
@@ -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:
|