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