DMA transfer form kernel to user space
You probably want to implement mmap
method of struct file_operations
. Consider:
static int
sample_drv_mem_mmap(struct file *filep, struct vm_area_struct *vma)
{
/*
* Set your "dev" pointer here (the one you used
* for dma_alloc_coherent() invocation)
*/
struct device *dev;
/*
* Set DMA address here (the one you obtained with
* dma_alloc_coherent() via its third argument)
*/
dma_addr_t dma_addr;
/* Set your DMA buffer size here */
size_t dma_size;
/* Physical page frame number to be derived from "dma_addr" */
unsigned long pfn;
/* Check the buffer size requested by the user */
if (vma->vm_end - vma->vm_start > dma_size)
return -EINVAL;
/*
* For the sake of simplicity, do not let the user specify an offset;
* you may want to take care of that in later versions of your code
*/
if (vma->vm_pgoff != 0)
return -EINVAL;
pfn = PHYS_PFN(dma_to_phys(dev, dma_addr));
return remap_pfn_range(vma, vma->vm_start, pfn,
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
}
/* ... */
static const struct file_operations sample_drv_fops = {
/* ... */
.mmap = sample_drv_mem_mmap,
/* ... */
};
Long story short, the idea is to convert the DMA (bus) address you have to a kernel physical address and then use remap_pfn_range()
to do the actual mapping between the kernel and the userland.
In the user application, one should invoke mmap()
to request the mapping (instead of the read / write
approach) For more information on that, please refer to man 2 mmap
on your system.