我是靠谱客的博主 快乐饼干,这篇文章主要介绍imx6ull的DMA实现的用户程序和驱动模块程序源码,现在分享给大家,希望可以做个参考。

imx6ull的DMA实现的用户程序和驱动模块程序源码

本文是使用正点原子阿尔法IMX6ULL开发板、ov5640摄像头、正点原子
1024*600的显示屏作为硬件基础编写的用户应用程序和内核驱动程序。
实现了Linux内核中DMA引擎驱动模块的功能,用户程序测试通过。
将该程序添加到调试好的ov5640程序中,做源地址和目的地址映射
并实现了传递图像的功能。由于无法解决源地址从ov5640取得数据和
写入LCD缓冲区的耗时问题,所以DMA并未实现希望的加快数据传递
的作用。但证明了可行性:DMA能正常使用,用户程序实现了将ov5640
的数据用DMA搬运到LCD上显示。
程序的关键步骤:
1、一是使用内核驱动模块的/dev/sdma_test中的ioctl函数将希望传入数据的
源地址映射到了内核空间,
用户程序中对该地址中的内容所做的更改都会在启动DMA传输后传输到DMA
的目的地址中。可以从内核驱动模块的打印中看出数据正确,完成了一次DMA传输。
2、二是用mmap函数和/dev/mem文件将内核中DMA的目的地址映射到用户空间中,
内核空间中目的地址的数据可以通过映射到用户空间的地址打印出来。DMA的目的地址
是通过dma驱动函数提供的read函数读出来的。如此,DMA的源地址和目的地址在内核
驱动模块程序中和在用户程序中都不一样,但做了映射,可以通过改变用户程序中的
源地址中的数据改变在用户程序中的目的地址中的数据内容。可以通过打印显示出来。
源代码分为:
1、内核驱动模块代码
2、用户程序代码
3、ov5640正常工作对应的内核设备树

1、内核驱动模块代码

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/dma-mapping.h>
#include <linux/fs.h>
#include <linux/dmaengine.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>

struct dma_private
{
struct miscdevice dma_misc_device;
struct device *dev;
char *wbuf;
char *rbuf;
struct dma_chan *dma_m2m_chan;
struct completion dma_m2m_ok;
dma_addr_t dma_src;
dma_addr_t dma_dst;
};

struct dma_private *dma_priv;

#define SDMA_BUF_SIZE (10246004)

static void dma_m2m_callback(void *data)
{
struct dma_private *dma_priv = data;
// dev_info(dma_priv->dev, “%sn finished DMA transaction” ,func);
complete(&dma_priv->dma_m2m_ok);
}

static int sdma_open(struct inode * inode, struct file * file)
{
// struct dma_private *dma_priv;
dma_priv = container_of(file->private_data,
struct dma_private, dma_misc_device);
dma_priv->wbuf = kzalloc(SDMA_BUF_SIZE, GFP_DMA);
if(!dma_priv->wbuf) {
dev_err(dma_priv->dev, “error allocating wbuf !!n”);
return -ENOMEM;
}
dma_priv->rbuf = kzalloc(SDMA_BUF_SIZE, GFP_DMA);
if(!dma_priv->rbuf) {
dev_err(dma_priv->dev, “error allocating rbuf !!n”);
return -ENOMEM;
}
dma_priv->dma_src = dma_map_single(dma_priv->dev, dma_priv->wbuf,
SDMA_BUF_SIZE, DMA_TO_DEVICE);
dma_priv->dma_dst = dma_map_single(dma_priv->dev, dma_priv->rbuf,
SDMA_BUF_SIZE, DMA_TO_DEVICE);
return 0;
}

static long sdma_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct dma_async_tx_descriptor *dma_m2m_desc;
struct dma_device *dma_dev;
// struct dma_private dma_priv;
dma_cookie_t cookie;
dma_priv = container_of(file->private_data,
struct dma_private, dma_misc_device);
dma_dev = dma_priv->dma_m2m_chan->device;
dma_priv->dma_src = dma_map_single(dma_priv->dev, dma_priv->wbuf,
SDMA_BUF_SIZE, DMA_TO_DEVICE);
dma_priv->dma_dst = dma_map_single(dma_priv->dev, dma_priv->rbuf,
SDMA_BUF_SIZE, DMA_TO_DEVICE);
// printk(“dma_src_addr=0x%xn”,dma_priv->dma_src);
// printk(“dma_dst_addr=0x%xn”,dma_priv->dma_dst);
dma_m2m_desc = dma_dev->device_prep_dma_memcpy(dma_priv->dma_m2m_chan,
dma_priv->dma_dst,
dma_priv->dma_src,
SDMA_BUF_SIZE,
DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
// dev_info(dma_priv->dev, “successful descriptor obtained”);
dma_m2m_desc->callback = dma_m2m_callback;
dma_m2m_desc->callback_param = dma_priv;
init_completion(&dma_priv->dma_m2m_ok);
cookie = dmaengine_submit(dma_m2m_desc);
if (dma_submit_error(cookie)){
dev_err(dma_priv->dev, “Failed to submit DMAn”);
return -EINVAL;
};
dma_async_issue_pending(dma_priv->dma_m2m_chan);
wait_for_completion(&dma_priv->dma_m2m_ok);
dma_async_is_tx_complete(dma_priv->dma_m2m_chan, cookie, NULL, NULL);
dma_unmap_single(dma_priv->dev, dma_priv->dma_src,
SDMA_BUF_SIZE, DMA_TO_DEVICE);
dma_unmap_single(dma_priv->dev, dma_priv->dma_dst,
SDMA_BUF_SIZE, DMA_TO_DEVICE);
if (
(dma_priv->rbuf) != *(dma_priv->wbuf)) {
dev_err(dma_priv->dev, “buffer copy failed!n”);
return -EINVAL;
}
// dev_info(dma_priv->dev, “buffer copy passed!n”);
// dev_info(dma_priv->dev, “wbuf is %sn”, dma_priv->wbuf);
// dev_info(dma_priv->dev, “rbuf is %sn”, dma_priv->rbuf);
// kfree(dma_priv->wbuf);
// kfree(dma_priv->rbuf);
return 0;
}

static int sdma_mmap(struct file *file, struct vm_area_struct *vma) {
// struct dma_private *dma_priv;
dma_priv = container_of(file->private_data,
struct dma_private, dma_misc_device);
//vma->vm_start是虚拟地址,dma_priv->dma_src >> PAGE_SHIFT是物理地址
if(remap_pfn_range(vma, vma->vm_start, dma_priv->dma_src >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
return 0;
}

static int sdma_read(struct file *filp, char __user * buf, size_t count, loff_t * offset) {
u8 databuf[4];
int err = 0;
databuf[0] = dma_priv->dma_dst;
databuf[1] = dma_priv->dma_dst>>8;
databuf[2] = dma_priv->dma_dst>>16;
databuf[3] = dma_priv->dma_dst>>24;
err = copy_to_user(buf, databuf, sizeof(databuf));
if(err < 0) {
printk(“kernel read failed!rn”);
return -EFAULT;
}
return 0;
}
struct file_operations dma_fops = {
.owner = THIS_MODULE,
.open = sdma_open,
.unlocked_ioctl = sdma_ioctl,
.mmap = sdma_mmap,
.read = sdma_read

};

static int __init my_probe(struct platform_device *pdev)
{
int retval;
struct dma_private *dma_device;
dma_cap_mask_t dma_m2m_mask;
dev_info(&pdev->dev, “platform_probe entern”);
dma_device = devm_kzalloc(&pdev->dev, sizeof(struct dma_private), GFP_KERNEL);
dma_device->dma_misc_device.minor = MISC_DYNAMIC_MINOR;
dma_device->dma_misc_device.name = “sdma_test”;
dma_device->dma_misc_device.fops = &dma_fops;
dma_device->dev = &pdev->dev;
dma_cap_zero(dma_m2m_mask);
dma_cap_set(DMA_MEMCPY, dma_m2m_mask);
dma_device->dma_m2m_chan = dma_request_channel(dma_m2m_mask, 0, NULL);
if (!dma_device->dma_m2m_chan) {
dev_err(&pdev->dev, “Error opening the SDMA memory to memory channeln”);
return -EINVAL;
}
retval = misc_register(&dma_device->dma_misc_device);
if (retval) return retval;
platform_set_drvdata(pdev, dma_device);
dev_info(&pdev->dev, “platform_probe exitn”);
return 0;
}

static int __exit my_remove(struct platform_device *pdev)
{
struct dma_private *dma_device = platform_get_drvdata(pdev);
dev_info(&pdev->dev, “platform_remove entern”);
misc_deregister(&dma_device->dma_misc_device);
dma_release_channel(dma_device->dma_m2m_chan);
dev_info(&pdev->dev, “platform_remove exitn”);
return 0;
}

static const struct of_device_id my_of_ids[] = {
{ .compatible = “arrow,sdma_m2m”},
{},
};

MODULE_DEVICE_TABLE(of, my_of_ids);

static struct platform_driver my_platform_driver = {
.probe = my_probe,
.remove = my_remove,
.driver = {
.name = “sdma_m2m”,
.of_match_table = my_of_ids,
.owner = THIS_MODULE,
}
};

static int demo_init(void)
{
int ret_val;
pr_info(“demo_init entern”);
ret_val = platform_driver_register(&my_platform_driver);
if (ret_val !=0)
{
pr_err(“platform value returned %dn”, ret_val);
return ret_val;
}
pr_info(“demo_init exitn”);
return 0;
}

static void demo_exit(void)
{
pr_info(“demo_exit entern”);
platform_driver_unregister(&my_platform_driver);
pr_info(“demo_exit exitn”);

}

module_init(demo_init);
module_exit(demo_exit);

MODULE_LICENSE(“GPL”);
MODULE_AUTHOR("hulei ");
MODULE_DESCRIPTION(“This is a SDMA mmap memory to memory driver”);

2、用户测试程序代码:

u_int8_t dma_src_to_dst(void)
{

// unsigned char * map_base;  
int fd_mem;  
// unsigned char *virtaddr;
// char string_to_pass[128]={'s','t'};
char string_to_pass[128]="string_to_pass";
unsigned long addr;  
unsigned char content;  
int  ret,i;
u_int8_t databuf[4];
u_int32_t dst_phy_addr;
    system("insmod dma5.ko");
my_dev = open("/dev/sdma_test", O_RDWR);
if (my_dev < 0) {
	perror("Fail to open device file: /dev/sdma_test.");
} else {

	ret = read(my_dev, databuf, sizeof(databuf));
	if(ret < 0) {
	printf("dst_phy_addr read failed!rn");
	}
	dst_phy_addr=(u_int32_t)databuf[3]<<24|databuf[2]<<16|databuf[1]<<8|databuf[0];
    	printf("dst_phy_addr=0x%xn",dst_phy_addr);
	virtaddr = (unsigned int *)mmap(0, SDMA_BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, my_dev, 0);
	// memset(string_to_pass,0x33,sizeof(string_to_pass));
	// strcpy(virtaddr, string_to_pass);
            printf("virtaddr=0x%xn",virtaddr);
	ioctl(my_dev, NULL);
	
	fd_mem = open("/dev/mem", O_RDWR|O_SYNC);  
	if (fd_mem == -1)  
	{
		printf(" error!n");  
	}  
		map_base = (unsigned int*)mmap(NULL, SDMA_BUF_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd_mem, (u_int32_t)dst_phy_addr);  
	if (map_base == 0)  
	{  
		printf("NULL pointer!n");  
	}  
	else
	{          
		printf("address: 0x%x",map_base);
		// printf("Successfull!n");  
	}
		printf("nstring_from_kernel_pass: %sn",map_base);
	// for (i=0;i < 0xf; i++)  
	// {  
	// 	addr = (unsigned long)(map_base + i); 
	// 	content =*(map_base+i);  
	// 	printf("address: 0x%lx   content 0x%xtt", addr, (unsigned int)content);  
	// }

	// close(fd_mem);

	// close(my_dev);

	// 	munmap(map_base, SDMA_BUF_SIZE);  

    //         system("rmmod dma5.ko");

}

return 0;

}

3、内核设备树文件

设备树添加节点
sdma_m2m{
compatible = “sdma_m2m”;
};
当然也可以在驱动中使用device_create函数,直接在insmod的时候在dev目录下
创建文件。请参考另一篇博客。
程序源代码下载链接:

程序代码:

最后

以上就是快乐饼干最近收集整理的关于imx6ull的DMA实现的用户程序和驱动模块程序源码的全部内容,更多相关imx6ull内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(65)

评论列表共有 0 条评论

立即
投稿
返回
顶部