[alsa-devel] ASoC problem
Hi,
I built linux-2.6.25.2 kernel with ASoC driver for SMDK2412 board. The following is dmesg,
Advanced Linux Sound Architecture Driver Version 1.0.16rc2 (Thu Jan 31 16:40:16 ASoC version 0.13.2
ALSA device list: No soundcards found.
I traced the soc_core.c and it never reaches soc_probe() routine. That's why "No soundcards found."
Could you give me some light ?
Appreciated!
On Thu, 2008-05-15 at 12:02 +0800, Alan Lu wrote:
Hi,
I built linux-2.6.25.2 kernel with ASoC driver for SMDK2412 board. The following is dmesg,
Advanced Linux Sound Architecture Driver Version 1.0.16rc2 (Thu Jan 31 16:40:16 ASoC version 0.13.2
ALSA device list: No soundcards found.
I traced the soc_core.c and it never reaches soc_probe() routine. That's why "No soundcards found."
Could you give me some light ?
Could you provide a little more information. It would be helpful to know what codec you are using. I suspect your codec/machine combination is not fully supported atm.
Liam
On Thu, May 15, 2008 at 12:02:46PM +0800, Alan Lu wrote:
I traced the soc_core.c and it never reaches soc_probe() routine. That's why "No soundcards found."
Could you give me some light ?
Your machine driver (or some other part of the system initialisation) should be registering a platform device with the name "soc-audio" and device data pointing to a struct snd_soc_device containing machine init functions.
Hi,
I tried "pcm" sample application which is coming along with the alsa-libs package (in the test folder). It works well for the sample rates supported by my audio driver but gives me a kernel crash when tried with any other non-supporting sample rate. If the driver has explicitly said that these sample rates are not-supported, then the app should have exited gracefully instead of trying further.
The log is as below (attached also):
[root@MY_EVM bin]# ./pcm -r 10000 -v Playback device is plughw:0,0 Stream parameters are 10000Hz, S16_LE, 1 channels Sine wave rate is 440.0000Hz Using transfer method: write Plug PCM: Rate conversion PCM (11025, sformat=S16_LE) Its setup is: Alignment trap: not handling instruction e1932f9f at [<c02317a0>]
access : RW_INTERLEAVEDUnhandled fault: alignment exception (0x001) at 0x00000003
format : S16_LE subInternal error: : 1 [#5] Modules linked in: CPU: 0 Not tainted (2.6.22.18-omap3 #1) PC is at snd_pcm_mmap_data_nopage+0xb8/0xe4 LR is at 0xc7b71c00 pc : [<c02317a4>] lr : [<c7b71c00>] psr: 60000113 sp : c69c3e58 ip : c77f9460 fp : c69c3e6c r10: 00000000 r9 : 402f2000 r8 : c7dc4f04 r7 : c77a7bd0 r6 : 00000000 r5 : c69c3e94 r4 : 402f2000 r3 : 00000003 r2 : bf3fe000 r1 : 00000000 r0 : c0be3540 Flags: nZCv IRQs on FIQs on Mode SVC_32 Segment user Control: 00c5387f Table: 807ec018 DAC: 00000015 Process pcm (pid: 324, stack limit = 0xc69c22d8) Stack: (0xc69c3e58 to 0xc69c4000) 3e40: 00000000 c69c2000 3e60: c69c3ec4 c69c3e70 c0092d2c c02316f8 c69c3e8c c69c3e80 c00580f4 c005c99c 3e80: 00000800 c0025380 000003c8 c07ed008 174c3094 00000002 17bfac7c c03a600c 3ea0: c055bd60 c77a7bd0 c00253b4 c0025380 c69c3fb0 402f2000 c69c3f04 c69c3ec8 3ec0: c0030fb0 c0092c08 174c3094 c0844123 0001f040 00000817 c055d6c0 c03a600c 3ee0: 00000817 c69c3fb0 402f2000 0008d3dd 00000000 00000000 c69c3fac c69c3f08 3f00: c002a1e8 c0030ed8 c03b22e4 c0844123 0001f040 00000004 c055d6c0 c002af68 3f20: c69c3f3c c69c3f30 c02356bc c0235134 c69c3f54 c69c3f40 c00b166c c0235694 3f40: c055d6c0 0001f040 c69c3f7c c69c3f58 c00b1910 c00b1644 00000025 c03b30d0 3f60: 00000004 0001f040 c0844123 c055d6c0 c69c3fa4 c69c3f80 c00b1968 c00b16bc 3f80: c69c3fac 00000000 0001ef20 0001eee0 ffffffff 00000000 00000000 00000000 3fa0: 00000000 c69c3fb0 c002ad60 c002a1b8 402f2000 00000000 00000000 00000000 3fc0: 00080000 00000000 00000000 00000000 0008d3dd 00000000 00000000 00020398 3fe0: 00000000 bed06588 40088d30 40088d58 20000010 ffffffff 00000000 00000000 Backtrace: [<c02316ec>] (snd_pcm_mmap_data_nopage+0x0/0xe4) from [<c0092d2c>] (__handle_mm_fault+0x130/0x968) r5:c69c2000 r4:00000000 [<c0092bfc>] (__handle_mm_fault+0x0/0x968) from [<c0030fb0>] (do_page_fault+0xe4/0x218) [<c0030ecc>] (do_page_fault+0x0/0x218) from [<c002a1e8>] (do_DataAbort+0x3c/0x9c) [<c002a1ac>] (do_DataAbort+0x0/0x9c) from [<c002ad60>] (ret_from_exception+0x0/0x10) Exception stack(0xc69c3fb0 to 0xc69c3ff8) 3fa0: 402f2000 00000000 00000000 00000000 3fc0: 00080000 00000000 00000000 00000000 0008d3dd 00000000 00000000 00020398 3fe0: 00000000 bed06588 40088d30 40088d58 20000010 ffffffff r7:00000000 r6:00000000 r5:00000000 r4:ffffffff Code: 0590300c 11a03000 e2833004 e1932f9f (e2822001) format : STD channels : 1 rate : 10000 exact rate : 10000 (10000/1) msbits : 16 buffer_size : 14860 period_size : 928 period_time : 92879 tick_time : 7812 tstamp_mode : NONE period_step : 1 sleep_min : 0 avail_min : 928 xfer_align : 1 start_threshold : 14848 stop_threshold : 14860 silence_threshold: 0 silence_size : 0 boundary : 973864960 Slave: Hardware PCM card 0 'TWL4030' device 0 subdevice 0 Its setup is: stream : PLAYBACK access : MMAP_INTERLEAVED format : S16_LE subformat : STD channels : 1 rate : 11025 exact rate : 11025 (11025/1) msbits : 16 buffer_size : 16384 period_size : 1024 period_time : 92879 tick_time : 7812 tstamp_mode : NONE period_step : 1 sleep_min : 0 avail_min : 1024 xfer_align : 1 start_threshold : 16384 stop_threshold : 16384 silence_threshold: 0 silence_size : 0 boundary : 1073741824 Segmentation fault
Is the driver not handling anything properly or is it the intended behavior? Please help.
Thanks and Regards, Anuj Aggarwal
At Thu, 15 May 2008 15:53:11 +0530, Aggarwal, Anuj wrote:
Hi,
I tried "pcm" sample application which is coming along with the alsa-libs package (in the test folder). It works well for the sample rates supported by my audio driver but gives me a kernel crash when tried with any other non-supporting sample rate. If the driver has explicitly said that these sample rates are not-supported, then the app should have exited gracefully instead of trying further.
Looks like a known long-standing problem with mmap of DMA pages. Does the patch below fix the problem (it's against the latest Linus git tree)? If not, which architecture is it?
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, };
It gave me the following error:
bash-3.00$ patch -p 1 < audio_patch (Stripping trailing CRs from patch.) patching file include/sound/memalloc.h Hunk #1 succeeded at 62 with fuzz 1. Hunk #2 FAILED at 87. 1 out of 2 hunks FAILED -- saving rejects to file include/sound/memalloc.h.rej (Stripping trailing CRs from patch.) patching file include/sound/pcm.h patch: **** malformed patch at line 60: @@ -306,6 +306,126 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
I think I have to apply the patch manually. Is there any other way to do that?
Thanks and Regards, Anuj Aggarwal
Platform Support Products Texas Instruments Inc Ph: +91-80-2509-9542 TI IP Ph: 509-9542 PSP Products RSS Feed PSP Product Announcements
-----Original Message----- From: Takashi Iwai [mailto:tiwai@suse.de] Sent: Thursday, May 15, 2008 3:58 PM To: Aggarwal, Anuj Cc: alsa-devel@alsa-project.org Subject: Re: [alsa-devel] Kernel crashes for unsupported sample rates
At Thu, 15 May 2008 15:53:11 +0530, Aggarwal, Anuj wrote:
Hi,
I tried "pcm" sample application which is coming along with the alsa-libs package (in the test folder). It works well for the sample rates supported by my audio driver but gives me a kernel crash when tried with any other non-supporting sample rate. If the driver has explicitly said that these sample rates are not-supported, then the app should have exited gracefully instead of trying further.
Looks like a known long-standing problem with mmap of DMA pages. Does the patch below fix the problem (it's against the latest Linus git tree)? If not, which architecture is it?
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, };
At Thu, 15 May 2008 16:40:52 +0530, Aggarwal, Anuj wrote:
It gave me the following error:
bash-3.00$ patch -p 1 < audio_patch (Stripping trailing CRs from patch.) patching file include/sound/memalloc.h Hunk #1 succeeded at 62 with fuzz 1. Hunk #2 FAILED at 87. 1 out of 2 hunks FAILED -- saving rejects to file include/sound/memalloc.h.rej (Stripping trailing CRs from patch.) patching file include/sound/pcm.h patch: **** malformed patch at line 60: @@ -306,6 +306,126 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
I think I have to apply the patch manually. Is there any other way to do that?
No. Please fix it manually.
Takashi
Can you point me to any particular git tree which I can download and apply the patches directly, instead of committing any silly mistake? It would be really helpful.
Thanks and Regards, Anuj Aggarwal
Platform Support Products Texas Instruments Inc Ph: +91-80-2509-9542 TI IP Ph: 509-9542 PSP Products RSS Feed PSP Product Announcements
-----Original Message----- From: Takashi Iwai [mailto:tiwai@suse.de] Sent: Thursday, May 15, 2008 5:58 PM To: Aggarwal, Anuj Cc: alsa-devel@alsa-project.org Subject: Re: [alsa-devel] Kernel crashes for unsupported sample rates
At Thu, 15 May 2008 16:40:52 +0530, Aggarwal, Anuj wrote:
It gave me the following error:
bash-3.00$ patch -p 1 < audio_patch (Stripping trailing CRs from patch.) patching file include/sound/memalloc.h Hunk #1 succeeded at 62 with fuzz 1. Hunk #2 FAILED at 87. 1 out of 2 hunks FAILED -- saving rejects to file include/sound/memalloc.h.rej (Stripping trailing CRs from patch.) patching file include/sound/pcm.h patch: **** malformed patch at line 60: @@ -306,6 +306,126 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
I think I have to apply the patch manually. Is there any other way to do that?
No. Please fix it manually.
Takashi
At Thu, 15 May 2008 18:09:21 +0530, Aggarwal, Anuj wrote:
Can you point me to any particular git tree which I can download and apply the patches directly, instead of committing any silly mistake? It would be really helpful.
You can try my experimental tree: git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-unstable-2.6.git
Takashi
I have tried to apply the patch manually but I couldn't because I am on kernel version 2.6.22.1.
Is the patch available for my kernel version? How should I go about it?
One observation I had was when I removed "SNDRV_PCM_INFO_MMAP" from the "pcm_hardware_playback", the kernel stopped crashing. It gave me some error and returned.
[root@OMAP3EVM bin]# [root@OMAP3EVM bin]# ./pcm -f cd -r 1000 Playback device is plughw:0,0 Stream parameters are 4000Hz, S16_LE, 1 channels Sine wave rate is 440.0000Hz Using transfer method: write ALSA lib pcm_plug.c:773:(snd_pcm_plug_hw_refine_schange) Unable to find an usable access for 'plughw:0,0' Rate 4000Hz not available for playback: Invalid argument Setting of hwparams failed: Invalid argument
Thanks and Regards, Anuj Aggarwal
Platform Support Products Texas Instruments Inc Ph: +91-80-2509-9542 TI IP Ph: 509-9542 PSP Products RSS Feed PSP Product Announcements
-----Original Message----- From: Takashi Iwai [mailto:tiwai@suse.de] Sent: Thursday, May 15, 2008 6:28 PM To: Aggarwal, Anuj Cc: alsa-devel@alsa-project.org Subject: Re: [alsa-devel] Kernel crashes for unsupported sample rates
At Thu, 15 May 2008 18:09:21 +0530, Aggarwal, Anuj wrote:
Can you point me to any particular git tree which I can download and apply the patches directly, instead of committing any silly mistake? It would be really helpful.
You can try my experimental tree: git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-unstable-2.6.git
Takashi
At Fri, 16 May 2008 17:16:18 +0530, Aggarwal, Anuj wrote:
I have tried to apply the patch manually but I couldn't because I am on kernel version 2.6.22.1.
Is the patch available for my kernel version?
No.
How should I go about it?
You can still try to resolve the conflicts manually. The patch is relatively straightforward.
One observation I had was when I removed "SNDRV_PCM_INFO_MMAP" from the "pcm_hardware_playback", the kernel stopped crashing. It gave me some error and returned.
Yes. The problem is the incosnsitency between ALSA DMA-mmap code dma_alloc_coherent() on some architectures.
Takashi
participants (5)
-
Aggarwal, Anuj
-
Alan Lu
-
Liam Girdwood
-
Mark Brown
-
Takashi Iwai