diff options
Diffstat (limited to 'sound/core/pcm_native.c')
-rw-r--r-- | sound/core/pcm_native.c | 83 |
1 files changed, 59 insertions, 24 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index ab73edf2c89a..29ab46a12e11 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/time.h> | 26 | #include <linux/time.h> |
27 | #include <linux/pm_qos_params.h> | 27 | #include <linux/pm_qos_params.h> |
28 | #include <linux/uio.h> | 28 | #include <linux/uio.h> |
29 | #include <linux/dma-mapping.h> | ||
29 | #include <sound/core.h> | 30 | #include <sound/core.h> |
30 | #include <sound/control.h> | 31 | #include <sound/control.h> |
31 | #include <sound/info.h> | 32 | #include <sound/info.h> |
@@ -3061,6 +3062,27 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file | |||
3061 | } | 3062 | } |
3062 | #endif /* coherent mmap */ | 3063 | #endif /* coherent mmap */ |
3063 | 3064 | ||
3065 | static inline struct page * | ||
3066 | snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs) | ||
3067 | { | ||
3068 | void *vaddr = substream->runtime->dma_area + ofs; | ||
3069 | #if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT) | ||
3070 | if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) | ||
3071 | return virt_to_page(CAC_ADDR(vaddr)); | ||
3072 | #endif | ||
3073 | #if defined(CONFIG_PPC32) && defined(CONFIG_NOT_COHERENT_CACHE) | ||
3074 | if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) { | ||
3075 | dma_addr_t addr = substream->runtime->dma_addr + ofs; | ||
3076 | addr -= get_dma_offset(substream->dma_buffer.dev.dev); | ||
3077 | /* assume dma_handle set via pfn_to_phys() in | ||
3078 | * mm/dma-noncoherent.c | ||
3079 | */ | ||
3080 | return pfn_to_page(addr >> PAGE_SHIFT); | ||
3081 | } | ||
3082 | #endif | ||
3083 | return virt_to_page(vaddr); | ||
3084 | } | ||
3085 | |||
3064 | /* | 3086 | /* |
3065 | * fault callback for mmapping a RAM page | 3087 | * fault callback for mmapping a RAM page |
3066 | */ | 3088 | */ |
@@ -3071,7 +3093,6 @@ static int snd_pcm_mmap_data_fault(struct vm_area_struct *area, | |||
3071 | struct snd_pcm_runtime *runtime; | 3093 | struct snd_pcm_runtime *runtime; |
3072 | unsigned long offset; | 3094 | unsigned long offset; |
3073 | struct page * page; | 3095 | struct page * page; |
3074 | void *vaddr; | ||
3075 | size_t dma_bytes; | 3096 | size_t dma_bytes; |
3076 | 3097 | ||
3077 | if (substream == NULL) | 3098 | if (substream == NULL) |
@@ -3081,36 +3102,53 @@ static int snd_pcm_mmap_data_fault(struct vm_area_struct *area, | |||
3081 | dma_bytes = PAGE_ALIGN(runtime->dma_bytes); | 3102 | dma_bytes = PAGE_ALIGN(runtime->dma_bytes); |
3082 | if (offset > dma_bytes - PAGE_SIZE) | 3103 | if (offset > dma_bytes - PAGE_SIZE) |
3083 | return VM_FAULT_SIGBUS; | 3104 | return VM_FAULT_SIGBUS; |
3084 | if (substream->ops->page) { | 3105 | if (substream->ops->page) |
3085 | page = substream->ops->page(substream, offset); | 3106 | page = substream->ops->page(substream, offset); |
3086 | if (!page) | 3107 | else |
3087 | return VM_FAULT_SIGBUS; | 3108 | page = snd_pcm_default_page_ops(substream, offset); |
3088 | } else { | 3109 | if (!page) |
3089 | vaddr = runtime->dma_area + offset; | 3110 | return VM_FAULT_SIGBUS; |
3090 | page = virt_to_page(vaddr); | ||
3091 | } | ||
3092 | get_page(page); | 3111 | get_page(page); |
3093 | vmf->page = page; | 3112 | vmf->page = page; |
3094 | return 0; | 3113 | return 0; |
3095 | } | 3114 | } |
3096 | 3115 | ||
3097 | static const struct vm_operations_struct snd_pcm_vm_ops_data = | 3116 | static const struct vm_operations_struct snd_pcm_vm_ops_data = { |
3098 | { | 3117 | .open = snd_pcm_mmap_data_open, |
3118 | .close = snd_pcm_mmap_data_close, | ||
3119 | }; | ||
3120 | |||
3121 | static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = { | ||
3099 | .open = snd_pcm_mmap_data_open, | 3122 | .open = snd_pcm_mmap_data_open, |
3100 | .close = snd_pcm_mmap_data_close, | 3123 | .close = snd_pcm_mmap_data_close, |
3101 | .fault = snd_pcm_mmap_data_fault, | 3124 | .fault = snd_pcm_mmap_data_fault, |
3102 | }; | 3125 | }; |
3103 | 3126 | ||
3127 | #ifndef ARCH_HAS_DMA_MMAP_COHERENT | ||
3128 | /* This should be defined / handled globally! */ | ||
3129 | #ifdef CONFIG_ARM | ||
3130 | #define ARCH_HAS_DMA_MMAP_COHERENT | ||
3131 | #endif | ||
3132 | #endif | ||
3133 | |||
3104 | /* | 3134 | /* |
3105 | * mmap the DMA buffer on RAM | 3135 | * mmap the DMA buffer on RAM |
3106 | */ | 3136 | */ |
3107 | static int snd_pcm_default_mmap(struct snd_pcm_substream *substream, | 3137 | static int snd_pcm_default_mmap(struct snd_pcm_substream *substream, |
3108 | struct vm_area_struct *area) | 3138 | struct vm_area_struct *area) |
3109 | { | 3139 | { |
3110 | area->vm_ops = &snd_pcm_vm_ops_data; | ||
3111 | area->vm_private_data = substream; | ||
3112 | area->vm_flags |= VM_RESERVED; | 3140 | area->vm_flags |= VM_RESERVED; |
3113 | atomic_inc(&substream->mmap_count); | 3141 | #ifdef ARCH_HAS_DMA_MMAP_COHERENT |
3142 | if (!substream->ops->page && | ||
3143 | substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) | ||
3144 | return dma_mmap_coherent(substream->dma_buffer.dev.dev, | ||
3145 | area, | ||
3146 | substream->runtime->dma_area, | ||
3147 | substream->runtime->dma_addr, | ||
3148 | area->vm_end - area->vm_start); | ||
3149 | #endif /* ARCH_HAS_DMA_MMAP_COHERENT */ | ||
3150 | /* mmap with fault handler */ | ||
3151 | area->vm_ops = &snd_pcm_vm_ops_data_fault; | ||
3114 | return 0; | 3152 | return 0; |
3115 | } | 3153 | } |
3116 | 3154 | ||
@@ -3118,12 +3156,6 @@ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream, | |||
3118 | * mmap the DMA buffer on I/O memory area | 3156 | * mmap the DMA buffer on I/O memory area |
3119 | */ | 3157 | */ |
3120 | #if SNDRV_PCM_INFO_MMAP_IOMEM | 3158 | #if SNDRV_PCM_INFO_MMAP_IOMEM |
3121 | static const struct vm_operations_struct snd_pcm_vm_ops_data_mmio = | ||
3122 | { | ||
3123 | .open = snd_pcm_mmap_data_open, | ||
3124 | .close = snd_pcm_mmap_data_close, | ||
3125 | }; | ||
3126 | |||
3127 | int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, | 3159 | int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, |
3128 | struct vm_area_struct *area) | 3160 | struct vm_area_struct *area) |
3129 | { | 3161 | { |
@@ -3133,8 +3165,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, | |||
3133 | #ifdef pgprot_noncached | 3165 | #ifdef pgprot_noncached |
3134 | area->vm_page_prot = pgprot_noncached(area->vm_page_prot); | 3166 | area->vm_page_prot = pgprot_noncached(area->vm_page_prot); |
3135 | #endif | 3167 | #endif |
3136 | area->vm_ops = &snd_pcm_vm_ops_data_mmio; | ||
3137 | area->vm_private_data = substream; | ||
3138 | area->vm_flags |= VM_IO; | 3168 | area->vm_flags |= VM_IO; |
3139 | size = area->vm_end - area->vm_start; | 3169 | size = area->vm_end - area->vm_start; |
3140 | offset = area->vm_pgoff << PAGE_SHIFT; | 3170 | offset = area->vm_pgoff << PAGE_SHIFT; |
@@ -3142,7 +3172,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, | |||
3142 | (substream->runtime->dma_addr + offset) >> PAGE_SHIFT, | 3172 | (substream->runtime->dma_addr + offset) >> PAGE_SHIFT, |
3143 | size, area->vm_page_prot)) | 3173 | size, area->vm_page_prot)) |
3144 | return -EAGAIN; | 3174 | return -EAGAIN; |
3145 | atomic_inc(&substream->mmap_count); | ||
3146 | return 0; | 3175 | return 0; |
3147 | } | 3176 | } |
3148 | 3177 | ||
@@ -3159,6 +3188,7 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, | |||
3159 | long size; | 3188 | long size; |
3160 | unsigned long offset; | 3189 | unsigned long offset; |
3161 | size_t dma_bytes; | 3190 | size_t dma_bytes; |
3191 | int err; | ||
3162 | 3192 | ||
3163 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 3193 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
3164 | if (!(area->vm_flags & (VM_WRITE|VM_READ))) | 3194 | if (!(area->vm_flags & (VM_WRITE|VM_READ))) |
@@ -3183,10 +3213,15 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, | |||
3183 | if (offset > dma_bytes - size) | 3213 | if (offset > dma_bytes - size) |
3184 | return -EINVAL; | 3214 | return -EINVAL; |
3185 | 3215 | ||
3216 | area->vm_ops = &snd_pcm_vm_ops_data; | ||
3217 | area->vm_private_data = substream; | ||
3186 | if (substream->ops->mmap) | 3218 | if (substream->ops->mmap) |
3187 | return substream->ops->mmap(substream, area); | 3219 | err = substream->ops->mmap(substream, area); |
3188 | else | 3220 | else |
3189 | return snd_pcm_default_mmap(substream, area); | 3221 | err = snd_pcm_default_mmap(substream, area); |
3222 | if (!err) | ||
3223 | atomic_inc(&substream->mmap_count); | ||
3224 | return err; | ||
3190 | } | 3225 | } |
3191 | 3226 | ||
3192 | EXPORT_SYMBOL(snd_pcm_mmap_data); | 3227 | EXPORT_SYMBOL(snd_pcm_mmap_data); |