Commit 3e9e3e71 authored by Takashi Iwai's avatar Takashi Iwai Committed by Linus Torvalds

[PATCH] sparc ALSA fix

sound/core/pcm_native.c was assuming that all architectures implement
io_remap_page_range() in the same way.  They don't, so the sparc64 build
broke.

mmap callback is added to PCM ops.  The driver can implement its own mmap
method.

Also, mmapping of the status and control records is available only on known
coherent architectures now.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 49f46c6f
......@@ -275,7 +275,6 @@ enum sndrv_pcm_subformat {
#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */
#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */
#define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */
#define SNDRV_PCM_INFO_MMAP_IOMEM 0x01000000 /* mmap on IO memory */
enum sndrv_pcm_state {
SNDRV_PCM_STATE_OPEN = 0, /* stream is open */
......
......@@ -97,6 +97,7 @@ typedef struct _snd_pcm_ops {
int (*silence)(snd_pcm_substream_t *substream, int channel,
snd_pcm_uframes_t pos, snd_pcm_uframes_t count);
struct page *(*page)(snd_pcm_substream_t *substream, unsigned long offset);
int (*mmap)(snd_pcm_substream_t *substream, struct vm_area_struct *vma);
int (*ack)(snd_pcm_substream_t *substream);
} snd_pcm_ops_t;
......@@ -938,6 +939,28 @@ int snd_pcm_lib_free_pages(snd_pcm_substream_t *substream);
#define snd_pcm_sgbuf_get_addr(sgbuf,ofs) snd_sgbuf_get_addr(sgbuf,ofs)
struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset);
/* handle mmap counter - PCM mmap callback should handle this counter properly */
static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area)
{
snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data;
atomic_inc(&substream->runtime->mmap_count);
}
static inline void snd_pcm_mmap_data_close(struct vm_area_struct *area)
{
snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data;
atomic_dec(&substream->runtime->mmap_count);
}
/* mmap for io-memory area */
#if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_ALPHA)
#define SNDRV_PCM_INFO_MMAP_IOMEM SNDRV_PCM_INFO_MMAP
int snd_pcm_lib_mmap_iomem(snd_pcm_substream_t *substream, struct vm_area_struct *area);
#else
#define SNDRV_PCM_INFO_MMAP_IOMEM 0
#define snd_pcm_lib_mmap_iomem NULL
#endif
static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max)
{
*max = dma < 4 ? 64 * 1024 : 128 * 1024;
......
......@@ -1050,6 +1050,9 @@ EXPORT_SYMBOL(snd_pcm_release);
EXPORT_SYMBOL(snd_pcm_playback_poll);
EXPORT_SYMBOL(snd_pcm_capture_poll);
EXPORT_SYMBOL(snd_pcm_mmap_data);
#if SNDRV_PCM_INFO_MMAP_IOMEM
EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
#endif
/* pcm_misc.c */
EXPORT_SYMBOL(snd_pcm_format_signed);
EXPORT_SYMBOL(snd_pcm_format_unsigned);
......
......@@ -2908,6 +2908,18 @@ unsigned int snd_pcm_capture_poll(struct file *file, poll_table * wait)
return mask;
}
/*
* mmap support
*/
/*
* Only on coherent architectures, we can mmap the status and the control records
* for effcient data transfer. On others, we have to use HWSYNC ioctl...
*/
#if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_ALPHA)
/*
* mmap status record
*/
static struct page * snd_pcm_mmap_status_nopage(struct vm_area_struct *area, unsigned long address, int *type)
{
snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data;
......@@ -2930,8 +2942,8 @@ static struct vm_operations_struct snd_pcm_vm_ops_status =
.nopage = snd_pcm_mmap_status_nopage,
};
int snd_pcm_mmap_status(snd_pcm_substream_t *substream, struct file *file,
struct vm_area_struct *area)
static int snd_pcm_mmap_status(snd_pcm_substream_t *substream, struct file *file,
struct vm_area_struct *area)
{
snd_pcm_runtime_t *runtime;
long size;
......@@ -2948,6 +2960,9 @@ int snd_pcm_mmap_status(snd_pcm_substream_t *substream, struct file *file,
return 0;
}
/*
* mmap control record
*/
static struct page * snd_pcm_mmap_control_nopage(struct vm_area_struct *area, unsigned long address, int *type)
{
snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data;
......@@ -2987,20 +3002,26 @@ static int snd_pcm_mmap_control(snd_pcm_substream_t *substream, struct file *fil
area->vm_flags |= VM_RESERVED;
return 0;
}
static void snd_pcm_mmap_data_open(struct vm_area_struct *area)
#else /* ! coherent mmap */
/*
* don't support mmap for status and control records.
*/
static int snd_pcm_mmap_status(snd_pcm_substream_t *substream, struct file *file,
struct vm_area_struct *area)
{
snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data;
atomic_inc(&substream->runtime->mmap_count);
return -ENXIO;
}
static void snd_pcm_mmap_data_close(struct vm_area_struct *area)
static int snd_pcm_mmap_control(snd_pcm_substream_t *substream, struct file *file,
struct vm_area_struct *area)
{
snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data;
atomic_dec(&substream->runtime->mmap_count);
return -ENXIO;
}
#endif /* coherent mmap */
static struct page * snd_pcm_mmap_data_nopage(struct vm_area_struct *area, unsigned long address, int *type)
/*
* nopage callback for mmapping a RAM page
*/
static struct page *snd_pcm_mmap_data_nopage(struct vm_area_struct *area, unsigned long address, int *type)
{
snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data;
snd_pcm_runtime_t *runtime;
......@@ -3040,12 +3061,52 @@ static struct vm_operations_struct snd_pcm_vm_ops_data =
.nopage = snd_pcm_mmap_data_nopage,
};
/*
* mmap the DMA buffer on RAM
*/
static int snd_pcm_default_mmap(snd_pcm_substream_t *substream, struct vm_area_struct *area)
{
area->vm_ops = &snd_pcm_vm_ops_data;
area->vm_private_data = substream;
area->vm_flags |= VM_RESERVED;
atomic_inc(&substream->runtime->mmap_count);
return 0;
}
/*
* mmap the DMA buffer on I/O memory area
*/
#if SNDRV_PCM_INFO_MMAP_IOMEM
static struct vm_operations_struct snd_pcm_vm_ops_data_mmio =
{
.open = snd_pcm_mmap_data_open,
.close = snd_pcm_mmap_data_close,
};
int snd_pcm_lib_mmap_iomem(snd_pcm_substream_t *substream, struct vm_area_struct *area)
{
long size;
unsigned long offset;
#ifdef pgprot_noncached
area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
#endif
area->vm_ops = &snd_pcm_vm_ops_data_mmio;
area->vm_flags |= VM_IO;
size = area->vm_end - area->vm_start;
offset = area->vm_pgoff << PAGE_SHIFT;
if (io_remap_page_range(area, area->vm_start,
substream->runtime->dma_addr + offset,
size, area->vm_page_prot))
return -EAGAIN;
atomic_inc(&substream->runtime->mmap_count);
return 0;
}
#endif /* SNDRV_PCM_INFO_MMAP */
/*
* mmap DMA buffer
*/
int snd_pcm_mmap_data(snd_pcm_substream_t *substream, struct file *file,
struct vm_area_struct *area)
{
......@@ -3078,19 +3139,10 @@ int snd_pcm_mmap_data(snd_pcm_substream_t *substream, struct file *file,
if (offset > dma_bytes - size)
return -EINVAL;
area->vm_ops = &snd_pcm_vm_ops_data;
area->vm_private_data = substream;
area->vm_flags |= VM_RESERVED;
if (runtime->hw.info & SNDRV_PCM_INFO_MMAP_IOMEM) {
area->vm_ops = &snd_pcm_vm_ops_data_mmio;
area->vm_flags |= VM_IO;
if (io_remap_page_range(area, area->vm_start,
runtime->dma_addr + offset,
size, area->vm_page_prot))
return -EAGAIN;
}
atomic_inc(&runtime->mmap_count);
return 0;
if (substream->ops->mmap)
return substream->ops->mmap(substream, area);
else
return snd_pcm_default_mmap(substream, area);
}
static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
......
......@@ -742,8 +742,7 @@ snd_nm256_capture_update(nm256_t *chip)
*/
static snd_pcm_hardware_t snd_nm256_playback =
{
.info = SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID|
SNDRV_PCM_INFO_MMAP_IOMEM|
.info = SNDRV_PCM_INFO_MMAP_IOMEM |SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
/*SNDRV_PCM_INFO_PAUSE |*/
SNDRV_PCM_INFO_RESUME,
......@@ -762,8 +761,7 @@ static snd_pcm_hardware_t snd_nm256_playback =
static snd_pcm_hardware_t snd_nm256_capture =
{
.info = SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID|
SNDRV_PCM_INFO_MMAP_IOMEM|
.info = SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
/*SNDRV_PCM_INFO_PAUSE |*/
SNDRV_PCM_INFO_RESUME,
......@@ -864,6 +862,7 @@ static snd_pcm_ops_t snd_nm256_playback_ops = {
.copy = snd_nm256_playback_copy,
.silence = snd_nm256_playback_silence,
#endif
.mmap = snd_pcm_lib_mmap_iomem,
};
static snd_pcm_ops_t snd_nm256_capture_ops = {
......@@ -877,6 +876,7 @@ static snd_pcm_ops_t snd_nm256_capture_ops = {
#ifndef __i386__
.copy = snd_nm256_capture_copy,
#endif
.mmap = snd_pcm_lib_mmap_iomem,
};
static int __devinit
......
......@@ -331,9 +331,8 @@ static int snd_rme32_capture_copy(snd_pcm_substream_t * substream, int channel,
* SPDIF I/O capabilites (half-duplex mode)
*/
static snd_pcm_hardware_t snd_rme32_spdif_info = {
.info = (SNDRV_PCM_INFO_MMAP |
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_SYNC_START),
......@@ -359,9 +358,8 @@ static snd_pcm_hardware_t snd_rme32_spdif_info = {
*/
static snd_pcm_hardware_t snd_rme32_adat_info =
{
.info = (SNDRV_PCM_INFO_MMAP |
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_SYNC_START),
......@@ -1246,6 +1244,7 @@ static snd_pcm_ops_t snd_rme32_playback_spdif_ops = {
.pointer = snd_rme32_playback_pointer,
.copy = snd_rme32_playback_copy,
.silence = snd_rme32_playback_silence,
.mmap = snd_pcm_lib_mmap_iomem,
};
static snd_pcm_ops_t snd_rme32_capture_spdif_ops = {
......@@ -1258,6 +1257,7 @@ static snd_pcm_ops_t snd_rme32_capture_spdif_ops = {
.trigger = snd_rme32_pcm_trigger,
.pointer = snd_rme32_capture_pointer,
.copy = snd_rme32_capture_copy,
.mmap = snd_pcm_lib_mmap_iomem,
};
static snd_pcm_ops_t snd_rme32_playback_adat_ops = {
......@@ -1270,6 +1270,7 @@ static snd_pcm_ops_t snd_rme32_playback_adat_ops = {
.pointer = snd_rme32_playback_pointer,
.copy = snd_rme32_playback_copy,
.silence = snd_rme32_playback_silence,
.mmap = snd_pcm_lib_mmap_iomem,
};
static snd_pcm_ops_t snd_rme32_capture_adat_ops = {
......@@ -1281,6 +1282,7 @@ static snd_pcm_ops_t snd_rme32_capture_adat_ops = {
.trigger = snd_rme32_pcm_trigger,
.pointer = snd_rme32_capture_pointer,
.copy = snd_rme32_capture_copy,
.mmap = snd_pcm_lib_mmap_iomem,
};
/* for fullduplex mode */
......
......@@ -383,9 +383,8 @@ snd_rme96_capture_copy(snd_pcm_substream_t *substream,
*/
static snd_pcm_hardware_t snd_rme96_playback_spdif_info =
{
.info = (SNDRV_PCM_INFO_MMAP |
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
......@@ -413,9 +412,8 @@ static snd_pcm_hardware_t snd_rme96_playback_spdif_info =
*/
static snd_pcm_hardware_t snd_rme96_capture_spdif_info =
{
.info = (SNDRV_PCM_INFO_MMAP |
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
......@@ -443,9 +441,8 @@ static snd_pcm_hardware_t snd_rme96_capture_spdif_info =
*/
static snd_pcm_hardware_t snd_rme96_playback_adat_info =
{
.info = (SNDRV_PCM_INFO_MMAP |
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
......@@ -469,9 +466,8 @@ static snd_pcm_hardware_t snd_rme96_playback_adat_info =
*/
static snd_pcm_hardware_t snd_rme96_capture_adat_info =
{
.info = (SNDRV_PCM_INFO_MMAP |
.info = (SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_MMAP_IOMEM |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
......@@ -1494,6 +1490,7 @@ static snd_pcm_ops_t snd_rme96_playback_spdif_ops = {
.pointer = snd_rme96_playback_pointer,
.copy = snd_rme96_playback_copy,
.silence = snd_rme96_playback_silence,
.mmap = snd_pcm_lib_mmap_iomem,
};
static snd_pcm_ops_t snd_rme96_capture_spdif_ops = {
......@@ -1505,6 +1502,7 @@ static snd_pcm_ops_t snd_rme96_capture_spdif_ops = {
.trigger = snd_rme96_capture_trigger,
.pointer = snd_rme96_capture_pointer,
.copy = snd_rme96_capture_copy,
.mmap = snd_pcm_lib_mmap_iomem,
};
static snd_pcm_ops_t snd_rme96_playback_adat_ops = {
......@@ -1517,6 +1515,7 @@ static snd_pcm_ops_t snd_rme96_playback_adat_ops = {
.pointer = snd_rme96_playback_pointer,
.copy = snd_rme96_playback_copy,
.silence = snd_rme96_playback_silence,
.mmap = snd_pcm_lib_mmap_iomem,
};
static snd_pcm_ops_t snd_rme96_capture_adat_ops = {
......@@ -1528,6 +1527,7 @@ static snd_pcm_ops_t snd_rme96_capture_adat_ops = {
.trigger = snd_rme96_capture_trigger,
.pointer = snd_rme96_capture_pointer,
.copy = snd_rme96_capture_copy,
.mmap = snd_pcm_lib_mmap_iomem,
};
static void
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment