aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/pcm_native.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/pcm_native.c')
-rw-r--r--sound/core/pcm_native.c44
1 files changed, 37 insertions, 7 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 14e32825c339..d233cb3b41d8 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -243,15 +243,29 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
static bool hw_support_mmap(struct snd_pcm_substream *substream)
{
+ struct snd_dma_buffer *dmabuf;
+
if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_MMAP))
return false;
- if (substream->ops->mmap ||
- (substream->dma_buffer.dev.type != SNDRV_DMA_TYPE_DEV &&
- substream->dma_buffer.dev.type != SNDRV_DMA_TYPE_DEV_UC))
+ if (substream->ops->mmap || substream->ops->page)
return true;
- return dma_can_mmap(substream->dma_buffer.dev.dev);
+ dmabuf = snd_pcm_get_dma_buf(substream);
+ if (!dmabuf)
+ dmabuf = &substream->dma_buffer;
+ switch (dmabuf->dev.type) {
+ case SNDRV_DMA_TYPE_UNKNOWN:
+ /* we can't know the device, so just assume that the driver does
+ * everything right
+ */
+ return true;
+ case SNDRV_DMA_TYPE_CONTINUOUS:
+ case SNDRV_DMA_TYPE_VMALLOC:
+ return true;
+ default:
+ return dma_can_mmap(dmabuf->dev.dev);
+ }
}
static int constrain_mask_params(struct snd_pcm_substream *substream,
@@ -3063,9 +3077,14 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
boundary = 0x7fffffff;
snd_pcm_stream_lock_irq(substream);
/* FIXME: we should consider the boundary for the sync from app */
- if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
- control->appl_ptr = scontrol.appl_ptr;
- else
+ if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) {
+ err = pcm_lib_apply_appl_ptr(substream,
+ scontrol.appl_ptr);
+ if (err < 0) {
+ snd_pcm_stream_unlock_irq(substream);
+ return err;
+ }
+ } else
scontrol.appl_ptr = control->appl_ptr % boundary;
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = scontrol.avail_min;
@@ -3602,6 +3621,12 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file
static bool pcm_status_mmap_allowed(struct snd_pcm_file *pcm_file)
{
+ /* If drivers require the explicit sync (typically for non-coherent
+ * pages), we have to disable the mmap of status and control data
+ * to enforce the control via SYNC_PTR ioctl.
+ */
+ if (pcm_file->substream->runtime->hw.info & SNDRV_PCM_INFO_EXPLICIT_SYNC)
+ return false;
/* See pcm_control_mmap_allowed() below.
* Since older alsa-lib requires both status and control mmaps to be
* coupled, we have to disable the status mmap for old alsa-lib, too.
@@ -3616,6 +3641,9 @@ static bool pcm_control_mmap_allowed(struct snd_pcm_file *pcm_file)
{
if (pcm_file->no_compat_mmap)
return false;
+ /* see above */
+ if (pcm_file->substream->runtime->hw.info & SNDRV_PCM_INFO_EXPLICIT_SYNC)
+ return false;
/* Disallow the 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.
@@ -3664,6 +3692,8 @@ static vm_fault_t snd_pcm_mmap_data_fault(struct vm_fault *vmf)
return VM_FAULT_SIGBUS;
if (substream->ops->page)
page = substream->ops->page(substream, offset);
+ else if (!snd_pcm_get_dma_buf(substream))
+ page = virt_to_page(runtime->dma_area + offset);
else
page = snd_sgbuf_get_page(snd_pcm_get_dma_buf(substream), offset);
if (!page)