ALSA fixes for non-coherent archs (Re: [PATCH] Sam440ep support)

Takashi Iwai tiwai at suse.de
Wed May 14 22:26:53 EST 2008


At Tue, 06 May 2008 11:16:22 +0200,
Gerhard Pircher wrote:
> 
> -------- Original-Nachricht --------
> > Datum: Tue, 06 May 2008 18:48:39 +1000
> > Von: Benjamin Herrenschmidt <benh at kernel.crashing.org>
> > An: Gerhard Pircher <gerhard_pircher at gmx.net>
> > CC: linuxppc-dev at ozlabs.org, Takashi Iwai <tiwai at suse.de>, cjg at cruxppc.org, galak at kernel.crashing.org
> > Betreff: Re: [PATCH] Sam440ep support
> 
> > 
> > On Tue, 2008-05-06 at 09:51 +0200, Gerhard Pircher wrote:
> > > Takashi Iwai posted a preliminary patch a long time ago. I tested it
> > > on my machine and it failed with non coherent scatter-gather DMA
> > > allocations (I guess almost all ALSA PCI drivers use SG DMA?).
> > 
> > How does Alsa allocate such SG ?
> I can't answer this question. *ducked* :-) Takashi?
> 
> FYI: I posted the results of the test with Takashi's dma_mmap_coherent
> patch here:
> http://ozlabs.org/pipermail/linuxppc-dev/2006-June/024078.html
> 
> On the other side it looks like this problem does not only affect ALSA.
> As far as I can tell also some V4L(2) drivers have a problem with mmaping
> non coherent DMA allocations, but I'm not sure (it's a long time since I
> did some tests with video cards on my AmigaOne).
> 
> Naturally I can do some tests, if you or Takashi come up with a new
> patch.

OK, here is another patch for testing.  Since I lost my old patch
somewhere (and it's not worth to dig the archive), I wrote it up
quickly from scratch.  This version should cover both SG and non-SG
buffers.  It's against the latest git tree.

The patch adds a hackish verison of dma_mmap_coherent() for some
architectures in sound/core/pcm_native.c.  I'm not sure whether this
works.  I just tested it on X86.  It'd be appreciated if someone can
test this.

Also, this disables HDSPM driver for non-X86/IA64 since the driver has
own copy and silence methods that are incompatible with the new
SG-buffer data.


And, yes, I know we need to clean up huge messes in ALSA memory
handling routines.  But, let's fix obvious bugs before starting a big
rewrite...


thanks,

Takashi

---

diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h
index ae2921d..ccf3dfa 100644
--- a/include/sound/memalloc.h
+++ b/include/sound/memalloc.h
@@ -62,6 +62,18 @@ struct snd_dma_buffer {
 	void *private_data;	/* private for allocator; don't touch */
 };
 
+/* needs to use dma_mmap_coherent() for pages allocated via
+ * dma_alloc_coherent()
+ */
+#ifdef CONFIG_HAS_DMA
+#if (defined(CONFIG_PPC32) && !defined(CONFIG_CONFIG_NOT_COHERENT_CACHE)) || \
+	defined(CONFIG_ARM) || \
+	defined(CONFIG_MIPS) || \
+	defined(CONFIG_PARISC)
+#define SND_NEEDS_DMA_MMAP_COHERENT
+#endif /* archs */
+#endif /* CONFIG_HAS_DMA */
+
 /*
  * Scatter-Gather generic device pages
  */
@@ -75,7 +87,9 @@ struct snd_sg_buf {
 	int pages;	/* allocated pages */
 	int tblsize;	/* allocated table size */
 	struct snd_sg_page *table;	/* address table */
+#ifndef SND_NEEDS_DMA_MMAP_COHERENT
 	struct page **page_table;	/* page table (for vmap/vunmap) */
+#endif
 	struct device *dev;
 };
 
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 51d58cc..2e68420 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -969,10 +969,25 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
 int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size);
 int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream);
 
+/*
+ * SG-buffer
+ */
 #define snd_pcm_substream_sgbuf(substream) ((substream)->runtime->dma_buffer_p->private_data)
 #define snd_pcm_sgbuf_pages(size) snd_sgbuf_aligned_pages(size)
 #define snd_pcm_sgbuf_get_addr(sgbuf,ofs) snd_sgbuf_get_addr(sgbuf,ofs)
+
+#ifdef SND_NEEDS_DMA_MMAP_COHERENT
+int snd_pcm_sgbuf_ops_copy(struct snd_pcm_substream *substream,
+			   int channel, snd_pcm_uframes_t pos,
+			   void __user *buf, snd_pcm_uframes_t count);
+int snd_pcm_sgbuf_ops_silence(struct snd_pcm_substream *substream, int channel, 
+			      snd_pcm_uframes_t pos, snd_pcm_uframes_t count);
+#define snd_pcm_sgbuf_ops_page		NULL
+#else
+#define snd_pcm_sgbuf_ops_copy		NULL
+#define snd_pcm_sgbuf_ops_silence	NULL
 struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned long offset);
+#endif
 
 /* handle mmap counter - PCM mmap callback should handle this counter properly */
 static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area)
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
index ff07b4a..9e57032 100644
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -306,6 +306,126 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
 
 EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
 
+#ifdef SND_NEEDS_DMA_MMAP_COHERENT
+/*
+ * snd_pcm_sgbuf_ops_copy - copy callback for DMA SG-buffer
+ */
+int snd_pcm_sgbuf_ops_copy(struct snd_pcm_substream *substream,
+			   int channel, snd_pcm_uframes_t pos,
+			   void __user *buf, snd_pcm_uframes_t count)
+{
+	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned int ofs, idx;
+	char *ptr;
+
+	if (channel < 0) {
+		pos = frames_to_bytes(runtime, pos);
+		count = frames_to_bytes(runtime, count);
+	} else {
+		pos = channel * (runtime->dma_bytes / runtime->channels) +
+			samples_to_bytes(runtime, pos);
+		count = samples_to_bytes(runtime, count);
+	}
+
+	idx = pos >> PAGE_SHIFT;
+	ofs = pos & (PAGE_SIZE - 1);
+	ptr = sgbuf->table[idx].buf + ofs;
+
+	for (;;) {
+		unsigned int size, ret;
+		size = count;
+		if (ofs + size > PAGE_SIZE)
+			size = PAGE_SIZE - ofs;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			ret = copy_from_user(ptr, buf, size);
+		else
+			ret = copy_to_user(buf, ptr, size);
+		if (ret)
+			return -EFAULT;
+		count -= size;
+		if (!count)
+			return 0;
+		ofs = 0;
+		idx++;
+		ptr = sgbuf->table[idx].buf;
+		buf += size;
+	}
+}
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_copy);
+
+/*
+ * snd_pcm_sgbuf_ops_silence - fill with silence data
+ */
+int snd_pcm_sgbuf_ops_silence(struct snd_pcm_substream *substream, int channel, 
+			      snd_pcm_uframes_t pos, snd_pcm_uframes_t count)
+{
+	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned int idx, ofs, width;
+	const char *silence;
+	char *ptr;
+
+	if (channel < 0) {
+		pos = frames_to_bytes(runtime, pos);
+		count = frames_to_bytes(runtime, count);
+	} else {
+		pos = channel * (runtime->dma_bytes / runtime->channels) +
+			samples_to_bytes(runtime, pos);
+		count = samples_to_bytes(runtime, count);
+	}
+
+	idx = pos >> PAGE_SHIFT;
+	if (idx >= (unsigned int)sgbuf->pages)
+		return -EFAULT;
+	ofs = pos & (PAGE_SIZE - 1);
+	ptr = sgbuf->table[idx].buf + ofs;
+
+	width = snd_pcm_format_physical_width(runtime->format);
+	if (width < 8) {
+		count /= 2;
+		width = 8;
+	}
+	width /= 8;
+	silence = snd_pcm_format_silence_64(runtime->format);
+
+	if (PAGE_SIZE % width) {
+		unsigned int pat = 0;
+		for (;;) {
+			*ptr = silence[pat];
+			pat = (pat + 1) % width;
+			count--;
+			if (!count)
+				return 0;
+			ofs++;
+			if (ofs == PAGE_SIZE) {
+				ofs = 0;
+				idx++;
+				ptr = sgbuf->table[idx].buf;
+			} else
+				ptr++;
+		}
+	} else {
+		for (;;) {
+			unsigned int size, samples;
+			size = count;
+			if (ofs + size > PAGE_SIZE)
+				size = PAGE_SIZE - ofs;
+			samples = bytes_to_samples(runtime, size);
+			snd_pcm_format_set_silence(runtime->format, ptr,
+						   samples);
+			count -= size;
+			if (!count)
+				return 0;
+			ofs = 0;
+			idx++;
+			ptr = sgbuf->table[idx].buf;
+		}
+	}
+}
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_silence);
+
+#else /* !SND_NEEDS_DMA_MMAP_COHERENT */
 /**
  * snd_pcm_sgbuf_ops_page - get the page struct at the given offset
  * @substream: the pcm substream instance
@@ -323,9 +443,10 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne
 		return NULL;
 	return sgbuf->page_table[idx];
 }
-
 EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
 
+#endif /* SND_NEEDS_DMA_MMAP_COHERENT */
+
 /**
  * snd_pcm_lib_malloc_pages - allocate the DMA buffer
  * @substream: the substream to allocate the DMA buffer to
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 61f5d42..e3f68d2 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -3124,19 +3124,96 @@ static struct vm_operations_struct snd_pcm_vm_ops_data =
 {
 	.open =		snd_pcm_mmap_data_open,
 	.close =	snd_pcm_mmap_data_close,
+};
+
+static struct vm_operations_struct snd_pcm_vm_ops_data_fault =
+{
+	.open =		snd_pcm_mmap_data_open,
+	.close =	snd_pcm_mmap_data_close,
 	.fault =	snd_pcm_mmap_data_fault,
 };
 
+#ifdef SND_NEEDS_DMA_MMAP_COHERENT
+
+/*
+ * FIXME!!
+ * dma_mmap_coherent is missing on most architectures...
+ */
+#ifndef CONFIG_ARM
+static int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma,
+			     void *cpu_addr, dma_addr_t handle, size_t size)
+{
+#if defined(CONFIG_PPC32) && !defined(CONFIG_CONFIG_NOT_COHERENT_CACHE)
+	cpu_addr = bus_to_virt(handle);
+#elif defined(CONFIG_MIPS)
+	cpu_addr = phys_to_virt(plat_dma_addr_to_phys(handle));
+#elif defined(CONFIG_PARISC)
+	cpu_addr = __va(handle);
+#endif
+	return remap_pfn_range(vma, vma->vm_start,
+			       page_to_pfn(virt_to_page(cpu_addr)),
+			       size, vma->vm_page_prot);
+}
+#endif /* !ARM */
+
+/*
+ * snd_pcm_sgbuf_ops_mmap - mmap SG DMA pages
+ */
+static int snd_pcm_mmap_sgbuf(struct snd_pcm_substream *substream,
+			      struct vm_area_struct *area)
+{
+	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
+	unsigned long start, offset, offset_saved, size;
+	int err = 0;
+
+	start = area->vm_start;
+	offset_saved = offset = area->vm_pgoff;
+	size = area->vm_end - area->vm_start;
+	size = PAGE_ALIGN(size);
+	while (size > 0) {
+		if (offset >= sgbuf->pages) {
+			err = -EFAULT;
+			break;
+		}
+		err = dma_mmap_coherent(sgbuf->dev, area,
+					sgbuf->table[offset].buf,
+					sgbuf->table[offset].addr,
+					PAGE_SIZE);
+		if (err < 0)
+			break;
+		offset++;
+		area->vm_start += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+	area->vm_start = start;
+	area->vm_pgoff = offset_saved;
+	return err;
+}
+#endif /* SND_NEEDS_DMA_MMAP_COHERENT */
+
 /*
  * mmap the DMA buffer on RAM
  */
 static int snd_pcm_default_mmap(struct snd_pcm_substream *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->mmap_count);
+#ifdef SND_NEEDS_DMA_MMAP_COHERENT
+	if (!substream->ops->page) {
+		switch (substream->dma_buffer.dev.type) {
+		case SNDRV_DMA_TYPE_DEV:
+			return dma_mmap_coherent(substream->dma_buffer.dev.dev,
+						 area,
+						 substream->runtime->dma_area,
+						 substream->runtime->dma_addr,
+						 area->vm_end - area->vm_start);
+		case SNDRV_DMA_TYPE_DEV_SG:
+			return snd_pcm_mmap_sgbuf(substream, area);
+		}
+	}
+#endif /* SND_NEEDS_DMA_MMAP_COHERENT */
+	/* mmap with fault handler */
+	area->vm_ops = &snd_pcm_vm_ops_data_fault;
 	return 0;
 }
 
@@ -3144,12 +3221,6 @@ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream,
  * 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(struct snd_pcm_substream *substream,
 			   struct vm_area_struct *area)
 {
@@ -3159,8 +3230,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
 #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_private_data = substream;
 	area->vm_flags |= VM_IO;
 	size = area->vm_end - area->vm_start;
 	offset = area->vm_pgoff << PAGE_SHIFT;
@@ -3168,7 +3237,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
 				(substream->runtime->dma_addr + offset) >> PAGE_SHIFT,
 				size, area->vm_page_prot))
 		return -EAGAIN;
-	atomic_inc(&substream->mmap_count);
 	return 0;
 }
 
@@ -3185,6 +3253,7 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
 	long size;
 	unsigned long offset;
 	size_t dma_bytes;
+	int err;
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		if (!(area->vm_flags & (VM_WRITE|VM_READ)))
@@ -3210,10 +3279,15 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
 	if (offset > dma_bytes - size)
 		return -EINVAL;
 
+	area->vm_ops = &snd_pcm_vm_ops_data;
+	area->vm_private_data = substream;
 	if (substream->ops->mmap)
-		return substream->ops->mmap(substream, area);
+		err = substream->ops->mmap(substream, area);
 	else
-		return snd_pcm_default_mmap(substream, area);
+		err = snd_pcm_default_mmap(substream, area);
+	if (!err)
+		atomic_inc(&substream->mmap_count);
+	return err;
 }
 
 EXPORT_SYMBOL(snd_pcm_mmap_data);
diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c
index cefd228..67c6631 100644
--- a/sound/core/sgbuf.c
+++ b/sound/core/sgbuf.c
@@ -46,12 +46,14 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
 		tmpb.bytes = PAGE_SIZE;
 		snd_dma_free_pages(&tmpb);
 	}
+#ifndef SND_NEEDS_DMA_MMAP_COHERENT
 	if (dmab->area)
 		vunmap(dmab->area);
+	kfree(sgbuf->page_table);
+#endif
 	dmab->area = NULL;
 
 	kfree(sgbuf->table);
-	kfree(sgbuf->page_table);
 	kfree(sgbuf);
 	dmab->private_data = NULL;
 	
@@ -77,9 +79,11 @@ void *snd_malloc_sgbuf_pages(struct device *device,
 	sgbuf->table = kcalloc(sgbuf->tblsize, sizeof(*sgbuf->table), GFP_KERNEL);
 	if (! sgbuf->table)
 		goto _failed;
+#ifndef SND_NEEDS_DMA_MMAP_COHERENT
 	sgbuf->page_table = kcalloc(sgbuf->tblsize, sizeof(*sgbuf->page_table), GFP_KERNEL);
 	if (! sgbuf->page_table)
 		goto _failed;
+#endif
 
 	/* allocate each page */
 	for (i = 0; i < pages; i++) {
@@ -91,14 +95,20 @@ void *snd_malloc_sgbuf_pages(struct device *device,
 		}
 		sgbuf->table[i].buf = tmpb.area;
 		sgbuf->table[i].addr = tmpb.addr;
+#ifndef SND_NEEDS_DMA_MMAP_COHERENT
 		sgbuf->page_table[i] = virt_to_page(tmpb.area);
+#endif
 		sgbuf->pages++;
 	}
 
 	sgbuf->size = size;
+#ifndef SND_NEEDS_DMA_MMAP_COHERENT
 	dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, PAGE_KERNEL);
 	if (! dmab->area)
 		goto _failed;
+#else
+	dmab->area = sgbuf->table[0].buf;
+#endif
 	return dmab->area;
 
  _failed:
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 7e47421..09af3f5 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -651,6 +651,7 @@ config SND_HDSP
 config SND_HDSPM
 	tristate "RME Hammerfall DSP MADI"
 	depends on SND
+	depends on X86 || ALPHA || IA64
 	select SND_HWDEP
 	select SND_RAWMIDI
 	select SND_PCM
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
index f9a58b4..222e599 100644
--- a/sound/pci/au88x0/au88x0_pcm.c
+++ b/sound/pci/au88x0/au88x0_pcm.c
@@ -409,6 +409,8 @@ static struct snd_pcm_ops snd_vortex_playback_ops = {
 	.prepare = snd_vortex_pcm_prepare,
 	.trigger = snd_vortex_pcm_trigger,
 	.pointer = snd_vortex_pcm_pointer,
+	.copy = snd_pcm_sgbuf_ops_copy,
+	.silence = snd_pcm_sgbuf_ops_silence,
 	.page = snd_pcm_sgbuf_ops_page,
 };
 
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 4ecdd63..49b8ebc 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -548,6 +548,7 @@ static struct snd_pcm_ops snd_bt87x_pcm_ops = {
 	.prepare = snd_bt87x_prepare,
 	.trigger = snd_bt87x_trigger,
 	.pointer = snd_bt87x_pointer,
+	.copy = snd_pcm_sgbuf_ops_copy,
 	.page = snd_pcm_sgbuf_ops_page,
 };
 
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index e16dc92..e2c3f3d 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -801,6 +801,8 @@ static struct snd_pcm_ops analog_playback_ops = {
 	.prepare = pcm_prepare,
 	.trigger = pcm_trigger,
 	.pointer = pcm_pointer,
+	.copy = snd_pcm_sgbuf_ops_copy,
+	.silence = snd_pcm_sgbuf_ops_silence,
 	.page = snd_pcm_sgbuf_ops_page,
 };
 static struct snd_pcm_ops analog_capture_ops = {
@@ -812,6 +814,7 @@ static struct snd_pcm_ops analog_capture_ops = {
 	.prepare = pcm_prepare,
 	.trigger = pcm_trigger,
 	.pointer = pcm_pointer,
+	.copy = snd_pcm_sgbuf_ops_copy,
 	.page = snd_pcm_sgbuf_ops_page,
 };
 #ifdef ECHOCARD_HAS_DIGITAL_IO
@@ -825,6 +828,8 @@ static struct snd_pcm_ops digital_playback_ops = {
 	.prepare = pcm_prepare,
 	.trigger = pcm_trigger,
 	.pointer = pcm_pointer,
+	.copy = snd_pcm_sgbuf_ops_copy,
+	.silence = snd_pcm_sgbuf_ops_silence,
 	.page = snd_pcm_sgbuf_ops_page,
 };
 #endif /* !ECHOCARD_HAS_VMIXER */
@@ -837,6 +842,7 @@ static struct snd_pcm_ops digital_capture_ops = {
 	.prepare = pcm_prepare,
 	.trigger = pcm_trigger,
 	.pointer = pcm_pointer,
+	.copy = snd_pcm_sgbuf_ops_copy,
 	.page = snd_pcm_sgbuf_ops_page,
 };
 #endif /* ECHOCARD_HAS_DIGITAL_IO */
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index cf9276d..2d72959 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -1323,6 +1323,8 @@ static struct snd_pcm_ops snd_emu10k1_playback_ops = {
 	.prepare =		snd_emu10k1_playback_prepare,
 	.trigger =		snd_emu10k1_playback_trigger,
 	.pointer =		snd_emu10k1_playback_pointer,
+	.copy =			snd_pcm_sgbuf_ops_copy,
+	.silence =		snd_pcm_sgbuf_ops_silence,
 	.page =			snd_pcm_sgbuf_ops_page,
 };
 
@@ -1347,6 +1349,8 @@ static struct snd_pcm_ops snd_emu10k1_efx_playback_ops = {
 	.prepare =		snd_emu10k1_efx_playback_prepare,
 	.trigger =		snd_emu10k1_efx_playback_trigger,
 	.pointer =		snd_emu10k1_efx_playback_pointer,
+	.copy =			snd_pcm_sgbuf_ops_copy,
+	.silence =		snd_pcm_sgbuf_ops_silence,
 	.page =			snd_pcm_sgbuf_ops_page,
 };
 
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index b3a618e..e5ac9e1 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1461,6 +1461,8 @@ static struct snd_pcm_ops azx_pcm_ops = {
 	.prepare = azx_pcm_prepare,
 	.trigger = azx_pcm_trigger,
 	.pointer = azx_pcm_pointer,
+	.copy = snd_pcm_sgbuf_ops_copy,
+	.silence = snd_pcm_sgbuf_ops_silence,
 	.page = snd_pcm_sgbuf_ops_page,
 };
 
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index 979f7da..7fcb3d7 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -1696,6 +1696,8 @@ static struct snd_pcm_ops snd_riptide_playback_ops = {
 	.hw_params = snd_riptide_hw_params,
 	.hw_free = snd_riptide_hw_free,
 	.prepare = snd_riptide_prepare,
+	.copy = snd_pcm_sgbuf_ops_copy,
+	.silence = snd_pcm_sgbuf_ops_silence,
 	.page = snd_pcm_sgbuf_ops_page,
 	.trigger = snd_riptide_trigger,
 	.pointer = snd_riptide_pointer,
@@ -1707,6 +1709,7 @@ static struct snd_pcm_ops snd_riptide_capture_ops = {
 	.hw_params = snd_riptide_hw_params,
 	.hw_free = snd_riptide_hw_free,
 	.prepare = snd_riptide_prepare,
+	.copy = snd_pcm_sgbuf_ops_copy,
 	.page = snd_pcm_sgbuf_ops_page,
 	.trigger = snd_riptide_trigger,
 	.pointer = snd_riptide_pointer,
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index bbcee2c..156e457 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -2081,6 +2081,8 @@ static struct snd_pcm_ops snd_trident_nx_playback_ops = {
 	.prepare =	snd_trident_playback_prepare,
 	.trigger =	snd_trident_trigger,
 	.pointer =	snd_trident_playback_pointer,
+	.copy =		snd_pcm_sgbuf_ops_copy,
+	.silence =	snd_pcm_sgbuf_ops_silence,
 	.page =		snd_pcm_sgbuf_ops_page,
 };
 
@@ -2126,6 +2128,8 @@ static struct snd_pcm_ops snd_trident_nx_foldback_ops = {
 	.prepare =	snd_trident_foldback_prepare,
 	.trigger =	snd_trident_trigger,
 	.pointer =	snd_trident_playback_pointer,
+	.copy =		snd_pcm_sgbuf_ops_copy,
+	.silence =	snd_pcm_sgbuf_ops_silence,
 	.page =		snd_pcm_sgbuf_ops_page,
 };
 
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index b585cc3..4a9f132 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -1304,6 +1304,8 @@ static struct snd_pcm_ops snd_via686_playback_ops = {
 	.prepare =	snd_via686_playback_prepare,
 	.trigger =	snd_via82xx_pcm_trigger,
 	.pointer =	snd_via686_pcm_pointer,
+	.copy =		snd_pcm_sgbuf_ops_copy,
+	.silence =	snd_pcm_sgbuf_ops_silence,
 	.page =		snd_pcm_sgbuf_ops_page,
 };
 
@@ -1317,6 +1319,7 @@ static struct snd_pcm_ops snd_via686_capture_ops = {
 	.prepare =	snd_via686_capture_prepare,
 	.trigger =	snd_via82xx_pcm_trigger,
 	.pointer =	snd_via686_pcm_pointer,
+	.copy =		snd_pcm_sgbuf_ops_copy,
 	.page =		snd_pcm_sgbuf_ops_page,
 };
 
@@ -1330,6 +1333,8 @@ static struct snd_pcm_ops snd_via8233_playback_ops = {
 	.prepare =	snd_via8233_playback_prepare,
 	.trigger =	snd_via82xx_pcm_trigger,
 	.pointer =	snd_via8233_pcm_pointer,
+	.copy =		snd_pcm_sgbuf_ops_copy,
+	.silence =	snd_pcm_sgbuf_ops_silence,
 	.page =		snd_pcm_sgbuf_ops_page,
 };
 
@@ -1343,6 +1348,8 @@ static struct snd_pcm_ops snd_via8233_multi_ops = {
 	.prepare =	snd_via8233_multi_prepare,
 	.trigger =	snd_via82xx_pcm_trigger,
 	.pointer =	snd_via8233_pcm_pointer,
+	.copy =		snd_pcm_sgbuf_ops_copy,
+	.silence =	snd_pcm_sgbuf_ops_silence,
 	.page =		snd_pcm_sgbuf_ops_page,
 };
 
@@ -1356,6 +1363,7 @@ static struct snd_pcm_ops snd_via8233_capture_ops = {
 	.prepare =	snd_via8233_capture_prepare,
 	.trigger =	snd_via82xx_pcm_trigger,
 	.pointer =	snd_via8233_pcm_pointer,
+	.copy =		snd_pcm_sgbuf_ops_copy,
 	.page =		snd_pcm_sgbuf_ops_page,
 };
 
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index 31f64ee..1431b08 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -803,6 +803,8 @@ static struct snd_pcm_ops snd_via686_playback_ops = {
 	.prepare =	snd_via82xx_pcm_prepare,
 	.trigger =	snd_via82xx_pcm_trigger,
 	.pointer =	snd_via686_pcm_pointer,
+	.copy =		snd_pcm_sgbuf_ops_copy,
+	.silence =	snd_pcm_sgbuf_ops_silence,
 	.page =		snd_pcm_sgbuf_ops_page,
 };
 
@@ -816,6 +818,7 @@ static struct snd_pcm_ops snd_via686_capture_ops = {
 	.prepare =	snd_via82xx_pcm_prepare,
 	.trigger =	snd_via82xx_pcm_trigger,
 	.pointer =	snd_via686_pcm_pointer,
+	.copy =		snd_pcm_sgbuf_ops_copy,
 	.page =		snd_pcm_sgbuf_ops_page,
 };
 



More information about the Linuxppc-dev mailing list