Non-Contiguous Buffers

If your hardware supports the page table as in emu10k1 or the buffer descriptors as in via82xx, you can use the scatter-gather (SG) DMA. ALSA provides an interface for handling SG-buffers. The API is provided in <sound/pcm.h>.

For creating the SG-buffer handler, call snd_pcm_lib_preallocate_pages() or snd_pcm_lib_preallocate_pages_for_all() with SNDRV_DMA_TYPE_DEV_SG in the PCM constructor like other PCI pre-allocator. You need to pass snd_dma_pci_data(pci), where pci is the struct pci_dev pointer of the chip as well. The struct snd_sg_buf instance is created as substream->dma_private. You can cast the pointer like:


  struct snd_sg_buf *sgbuf = (struct snd_sg_buf *)substream->dma_private;

          

Then call snd_pcm_lib_malloc_pages() in the hw_params callback as well as in the case of normal PCI buffer. The SG-buffer handler will allocate the non-contiguous kernel pages of the given size and map them onto the virtually contiguous memory. The virtual pointer is addressed in runtime->dma_area. The physical address (runtime->dma_addr) is set to zero, because the buffer is physically non-contiguous. The physical address table is set up in sgbuf->table. You can get the physical address at a certain offset via snd_pcm_sgbuf_get_addr().

When a SG-handler is used, you need to set snd_pcm_sgbuf_ops_page as the page callback. (See page callback section.)

To release the data, call snd_pcm_lib_free_pages() in the hw_free callback as usual.