From: Takashi Iwai <tiwai@suse.de>

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.

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/include/sound/asound.h  |    1 
 25-akpm/include/sound/pcm.h     |   23 +++++++++
 25-akpm/sound/core/pcm.c        |    3 +
 25-akpm/sound/core/pcm_native.c |  100 ++++++++++++++++++++++++++++++----------
 25-akpm/sound/pci/nm256/nm256.c |    8 +--
 25-akpm/sound/pci/rme32.c       |   10 ++--
 25-akpm/sound/pci/rme96.c       |   16 +++---
 7 files changed, 120 insertions(+), 41 deletions(-)

diff -puN include/sound/asound.h~sparc-alsa-fix include/sound/asound.h
--- 25/include/sound/asound.h~sparc-alsa-fix	2004-09-01 23:33:25.000000000 -0700
+++ 25-akpm/include/sound/asound.h	2004-09-01 23:33:25.000000000 -0700
@@ -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 */
diff -puN include/sound/pcm.h~sparc-alsa-fix include/sound/pcm.h
--- 25/include/sound/pcm.h~sparc-alsa-fix	2004-09-01 23:33:25.000000000 -0700
+++ 25-akpm/include/sound/pcm.h	2004-09-01 23:33:25.000000000 -0700
@@ -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_subst
 #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;
diff -puN sound/core/pcm.c~sparc-alsa-fix sound/core/pcm.c
--- 25/sound/core/pcm.c~sparc-alsa-fix	2004-09-01 23:33:25.000000000 -0700
+++ 25-akpm/sound/core/pcm.c	2004-09-01 23:33:25.000000000 -0700
@@ -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);
diff -puN sound/core/pcm_native.c~sparc-alsa-fix sound/core/pcm_native.c
--- 25/sound/core/pcm_native.c~sparc-alsa-fix	2004-09-01 23:33:25.000000000 -0700
+++ 25-akpm/sound/core/pcm_native.c	2004-09-01 23:33:25.000000000 -0700
@@ -2908,6 +2908,18 @@ unsigned int snd_pcm_capture_poll(struct
 	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_p
 	.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_substrea
 	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_
 	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_p
 	.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_
 	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)
diff -puN sound/pci/nm256/nm256.c~sparc-alsa-fix sound/pci/nm256/nm256.c
--- 25/sound/pci/nm256/nm256.c~sparc-alsa-fix	2004-09-01 23:33:25.000000000 -0700
+++ 25-akpm/sound/pci/nm256/nm256.c	2004-09-01 23:33:25.000000000 -0700
@@ -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_play
 
 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_
 	.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_o
 #ifndef __i386__
 	.copy =		snd_nm256_capture_copy,
 #endif
+	.mmap =		snd_pcm_lib_mmap_iomem,
 };
 
 static int __devinit
diff -puN sound/pci/rme32.c~sparc-alsa-fix sound/pci/rme32.c
--- 25/sound/pci/rme32.c~sparc-alsa-fix	2004-09-01 23:33:25.000000000 -0700
+++ 25-akpm/sound/pci/rme32.c	2004-09-01 23:33:25.000000000 -0700
@@ -331,9 +331,8 @@ static int snd_rme32_capture_copy(snd_pc
  * 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_spdi
  */
 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_
 	.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_s
 	.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_
 	.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_a
 	.trigger =	snd_rme32_pcm_trigger,
 	.pointer =	snd_rme32_capture_pointer,
 	.copy =		snd_rme32_capture_copy,
+	.mmap =		snd_pcm_lib_mmap_iomem,
 };
 
 /* for fullduplex mode */
diff -puN sound/pci/rme96.c~sparc-alsa-fix sound/pci/rme96.c
--- 25/sound/pci/rme96.c~sparc-alsa-fix	2004-09-01 23:33:25.000000000 -0700
+++ 25-akpm/sound/pci/rme96.c	2004-09-01 23:33:25.000000000 -0700
@@ -383,9 +383,8 @@ snd_rme96_capture_copy(snd_pcm_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_play
  */
 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_capt
  */
 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_play
  */
 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_
 	.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_s
 	.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_
 	.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_a
 	.trigger =	snd_rme96_capture_trigger,
 	.pointer =	snd_rme96_capture_pointer,
 	.copy =		snd_rme96_capture_copy,
+	.mmap =		snd_pcm_lib_mmap_iomem,
 };
 
 static void
_