[alsa-devel] Audio DMA buffer layout
korbse at gmx.at
Thu May 10 12:52:20 CEST 2007
Thus spake Takashi Iwai:
First of all, thanks for your answer. However,
> At Tue, 08 May 2007 13:47:47 +0200,
> Markus Korber wrote:
>> IRQ1 +----------------+
>> | page_3 (right) |\
>> +----------------+ > double buffer 1
>> | page_2 (left) |/
>> IRQ0 +----------------+
>> | page_1 (right) |\
>> +----------------+ > double buffer 0
>> | page_0 (left) |/
> If I understand correctly, the samples for a channel (e.g. left) is
> practically split to two regions, page 0 and page 2 in the above?
> If yes, this h/w design is hard to implement mmap mode
> straightforwardly because the alsa-lib (and apps) assume "linear"
> buffers. For normal read/write without mmap, this shouldn't be that
> hard as you guess, though.
Are there any drawbacks if I use the R/W mode without mmap, regarding
applications (mplayer), dmix, etc.?
Furthermore, in mmap mode, I think I could use an intermediate buffer
(with the layout as above), where I copy the data from the (linear)
mmap'd buffer to, could I? Maybe using helpers from struct
pcm-indirect.h? But this is not very beautiful.
> A workaround would be to use SG-buffer (if possible). The constraint
> is thta both double buffers above have to be aligned in PAGE_SIZE
> (depending on architecture, 4KB mostly).
It's a custom chip with an ARM core and an AMBA-AHB bus. PAGE_SIZE
alignment wouldn't be a problem, although then buffer_size would be
fixed to multiples of PAGE_SIZE, i guess?
I'm not quite sure how to implement this:
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL), PAGE_SIZE, PAGE_SIZE)
- map sg-pages with snd_pcm_sgbuf_get_addr()
I mean, my hardware DMA layout is fixed (apart from the double buffer
page sizes, which should be a multiple of PAGE_SIZE).
So do I have to call snd_pcm_lib_malloc_pages() and/or do I need to call
dma_map_sg() with a scatterlist? Or how do I tell ALSA about my DMA
layout? And how is the application informed about this?
> For implementing a SG buffer, you can use either mmap or page pcm_ops.
> The mmap is to do the whole mmap operation, so you can do all what
> you'd like.
My understanding is, that the application mmap's my allocated buffer
(currently allocated with dma_alloc_writecombine) and the ALSA library
tells it, where it is allowed to put its data. (ALSA gets this info
through the pointer() callback and calls to snd_pcm_period_elapsed.)
Thus, this mmap() callback is only called once in normal mmap mode.
Now, if I would use a SG approach, how would I handle this mmap
operation in my callback? I guess, I have to provide similar
functionality as in dma_mmap() but with 2 different base addresses?
> The page is a callback used by the default ALSA mmap handler and you
> can return the page pointer corresponding to the given buffer offset.
This approach looks easier to me. Am I right, that here I would just
call snd_pcm_sgbuf_ops_page() from my page() callback handler? What
else do I need to do in this case to let the application know which
buffer it should fill?
More information about the Alsa-devel