当前位置: 首页 > news >正文

机构网站源码百度热搜词排行榜

机构网站源码,百度热搜词排行榜,求职网站建设如何完善,贵阳网站建设咨询为什么要实现自定义AXI DMA驱动 ZYNQ 的 AXI DMA 在 Direct Register DMA (即 Simple DMA)模式下可以通过 AXIS 总线的 tlast 提前结束传输,同时还可以在 BUFFLEN 寄存器中读取到实际传输的字节数,但是通过 Linux 的 DMA 驱动框架…

为什么要实现自定义AXI DMA驱动

ZYNQ 的 AXI DMA 在 Direct Register DMA (即 Simple DMA)模式下可以通过 AXIS 总线的 tlast 提前结束传输,同时还可以在 BUFFLEN 寄存器中读取到实际传输的字节数,但是通过 Linux 的 DMA 驱动框架控制 AXI DMA 时无法获取实际传输的字节数,因此这里便基于字符设备驱动框架实现一个 AXI DMA 的驱动(只支持 Simple 模式)。

AXI DMA IP配置

在这里插入图片描述

设备树修改

  1. 在顶层设备树根节点中加入如下节点
	axi_dma_test0: dma_test@0{compatible = "user_axi_dma";						/* 用于设备树与驱动进行匹配 */status = "okay";									/* 状态 */interrupt-names = "mm2s_introut", "s2mm_introut";	/* 中断名称 */interrupt-parent = <&intc>;							/* 中断控制器 */interrupts = <0 29 4 0 30 4>;						/* mm2s中断类型、中断号、触发方式,s2mm中断类型、中断号、触发方式,需要结合Vivado的配置 */reg = <0x40400000 0x10000>;							/* 控制寄存器 */buffer-max = <512>;									/* 收发缓冲区大小,不能超过DMA最大传输字节数 */};
  1. 在顶层设备树中引用axi_dma_0节点,并加入如下内容
&axi_dma_0 {compatible = "unused-xlnx-axi-dma-driver";				/* 修改compatible属性,不使用赛灵思的AXI DMA驱动 */
};

Linux驱动代码

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/poll.h>
#include <linux/ioport.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/skbuff.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>#define USER_AXI_DMA_MAX_MINORS		10#define XAXIDMA_CR_OFFSET			0x00000000		/* Channel control */
#define XAXIDMA_SR_OFFSET			0x00000004		/* Status */
#define XAXIDMA_SRCADDR_OFFSET		0x00000018		/* Simple mode source address pointer */
#define XAXIDMA_DESTADDR_OFFSET		0x00000018		/* Simple mode destination address pointer */
#define XAXIDMA_SRCADDR_MSB_OFFSET	0x0000001C		/* Simple mode source address pointer */
#define XAXIDMA_BUFFLEN_OFFSET		0x00000028		/* Tail descriptor pointer */#define XAXIDMA_CR_RUNSTOP_MASK		0x00000001 		/* Start/stop DMA channel */
#define XAXIDMA_CR_RESET_MASK		0x00000004 		/* Reset DMA engine */
#define XAXIDMA_CR_KEYHOLE_MASK		0x00000008 		/* Keyhole feature */
#define XAXIDMA_CR_CYCLIC_MASK		0x00000010 		/* Cyclic Mode */#define XAXIDMA_IRQ_IOC_MASK		0x00001000 		/* Completion intr */
#define XAXIDMA_IRQ_DELAY_MASK		0x00002000 		/* Delay interrupt */
#define XAXIDMA_IRQ_ERROR_MASK		0x00004000 		/* Error interrupt */
#define XAXIDMA_IRQ_ALL_MASK		0x00007000 		/* All interrupts */struct user_axi_dma {//cdev对象struct cdev cdev;//次设备号unsigned long minor;//设备IDdev_t devt;//打开标志atomic_t open_flag;//mm2s等待队列uint32_t mm2s_result;struct wait_queue_head mm2s_wq;//s2mm等待队列struct wait_queue_head s2mm_wq;//s2mm skbuffstruct sk_buff_head s2mm_skbuff;//MM2S的中断号int mm2s_irq;//S2MM的中断号int s2mm_irq;//MM2S中断名称char mm2s_irq_name[32];//S2MM中断名称char s2mm_irq_name[32];//IO内存虚拟地址void __iomem *base_addr;//mm2s bufferuint8_t *mm2s_buffer;dma_addr_t mm2s_phy;//s2mm bufferuint8_t *s2mm_buffer;dma_addr_t s2mm_phy;//DMA缓冲区最大大小uint32_t buffer_max;
};//起始设备号
static dev_t user_axi_dma_major;
//class对象
static struct class *user_axi_dma_class;
//IAD,用于管理次设备号
static DEFINE_IDA(user_axi_dma_ida);static void mm2s_transfer(struct user_axi_dma *user_axi_dma, dma_addr_t mm2s_buffer, uint32_t length)
{uint32_t cr_reg;iowrite32(mm2s_buffer, user_axi_dma->base_addr + 0x00000000 + XAXIDMA_SRCADDR_OFFSET);cr_reg = ioread32(user_axi_dma->base_addr + 0x00000000 + XAXIDMA_CR_OFFSET);iowrite32(cr_reg | XAXIDMA_CR_RUNSTOP_MASK, user_axi_dma->base_addr + 0x00000000 + XAXIDMA_CR_OFFSET);iowrite32(length, user_axi_dma->base_addr + 0x00000000 + XAXIDMA_BUFFLEN_OFFSET);
}static void s2mm_transfer(struct user_axi_dma *user_axi_dma, dma_addr_t s2mm_buffer, u32 length)
{uint32_t cr_reg;iowrite32(s2mm_buffer, user_axi_dma->base_addr + 0x00000030 + XAXIDMA_DESTADDR_OFFSET);cr_reg = ioread32(user_axi_dma->base_addr + 0x00000030 + XAXIDMA_CR_OFFSET);iowrite32(cr_reg | XAXIDMA_CR_RUNSTOP_MASK, user_axi_dma->base_addr + 0x00000030 + XAXIDMA_CR_OFFSET);iowrite32(length, user_axi_dma->base_addr + 0x00000030 + XAXIDMA_BUFFLEN_OFFSET);
}static irqreturn_t mm2s_interrupt(int irq, void *d)
{int count;uint32_t irq_status;uint32_t mm2s_cr;uint32_t s2mm_cr;uint32_t mm2s_bufflen;struct user_axi_dma *user_axi_dma = d;//读取待处理的中断irq_status = ioread32(user_axi_dma->base_addr + 0x00000000 + XAXIDMA_SR_OFFSET) & XAXIDMA_IRQ_ALL_MASK;//确认待处理的中断iowrite32(irq_status & XAXIDMA_IRQ_ALL_MASK, user_axi_dma->base_addr + 0x00000000 + XAXIDMA_SR_OFFSET);//mm2s出错if((irq_status & XAXIDMA_IRQ_ERROR_MASK)) {//复位DMA控制器iowrite32(XAXIDMA_CR_RESET_MASK, user_axi_dma->base_addr + 0x00000000 + XAXIDMA_CR_OFFSET);//等待复位完成for(count = 0; count < 2000; count++){mm2s_cr = ioread32(user_axi_dma->base_addr + 0x00000000 + XAXIDMA_CR_OFFSET);s2mm_cr = ioread32(user_axi_dma->base_addr + 0x00000030 + XAXIDMA_CR_OFFSET);if(((mm2s_cr & XAXIDMA_CR_RESET_MASK) == 0) && ((s2mm_cr & XAXIDMA_CR_RESET_MASK) == 0))break;}//传输结果为0xFFFFFFFF,表示失败user_axi_dma->mm2s_result = 0xFFFFFFFF;}else{//获取DMA实际发送长度mm2s_bufflen = ioread32(user_axi_dma->base_addr + 0x00000000 + XAXIDMA_BUFFLEN_OFFSET);//传输结果,成功为传输长度,失败为0xFFFFFFFFuser_axi_dma->mm2s_result = (mm2s_bufflen > 0) ? mm2s_bufflen : 0xFFFFFFFF;}//通过等待队列唤醒正在进行写操作的线程wake_up_interruptible(&user_axi_dma->mm2s_wq);return IRQ_HANDLED;
}static irqreturn_t s2mm_interrupt(int irq, void *d)
{int count;uint32_t irq_status;uint32_t mm2s_cr;uint32_t s2mm_cr;uint32_t s2mm_bufflen;struct sk_buff *skb;struct user_axi_dma *user_axi_dma = d;//读取待处理的中断irq_status = ioread32(user_axi_dma->base_addr + 0x00000030 + XAXIDMA_SR_OFFSET) & XAXIDMA_IRQ_ALL_MASK;//确认待处理的中断iowrite32(irq_status & XAXIDMA_IRQ_ALL_MASK, user_axi_dma->base_addr + 0x00000030 + XAXIDMA_SR_OFFSET);//s2mm出错if((irq_status & XAXIDMA_IRQ_ERROR_MASK)) {//复位DMA控制器iowrite32(XAXIDMA_CR_RESET_MASK, user_axi_dma->base_addr + 0x00000000 + XAXIDMA_CR_OFFSET);//等待复位完成for(count = 0; count < 2000; count++){mm2s_cr = ioread32(user_axi_dma->base_addr + 0x00000000 + XAXIDMA_CR_OFFSET);s2mm_cr = ioread32(user_axi_dma->base_addr + 0x00000030 + XAXIDMA_CR_OFFSET);if(((mm2s_cr & XAXIDMA_CR_RESET_MASK) == 0) && ((s2mm_cr & XAXIDMA_CR_RESET_MASK) == 0))break;}}else{//获取DMA实际接收长度s2mm_bufflen = ioread32(user_axi_dma->base_addr + 0x00000030 + XAXIDMA_BUFFLEN_OFFSET);if(s2mm_bufflen == 0)return IRQ_HANDLED;//确保skbuff中最大包含8个skb,避免内存消耗过大while(skb_queue_len(&user_axi_dma->s2mm_skbuff) > 8){skb = skb_dequeue(&user_axi_dma->s2mm_skbuff);kfree_skb(skb);}//分配skbskb = alloc_skb(s2mm_bufflen, GFP_ATOMIC);if(!skb)return IRQ_HANDLED;//将数据拷贝到skpmemcpy(skb_put(skb, s2mm_bufflen), user_axi_dma->s2mm_buffer, s2mm_bufflen);//将skp添加到skp队列skb_queue_tail(&user_axi_dma->s2mm_skbuff, skb);//通过等待队列唤醒正在进行读操作的线程wake_up_interruptible(&user_axi_dma->s2mm_wq);}//重新启动DMA接收s2mm_transfer(user_axi_dma, user_axi_dma->s2mm_phy, user_axi_dma->buffer_max);return IRQ_HANDLED;
}static int user_axi_dma_open(struct inode *inode, struct file *p_file)
{int result;int count;uint32_t mm2s_cr;uint32_t s2mm_cr;struct sk_buff *skb;struct user_axi_dma *user_axi_dma = container_of(inode->i_cdev, struct user_axi_dma, cdev);unsigned long irqflags = IRQF_SHARED | IRQF_ONESHOT;//若已经被打开则返回busyif(!atomic_dec_and_test(&user_axi_dma->open_flag)){atomic_inc(&user_axi_dma->open_flag);return -EBUSY;}//设置文件私有数据p_file->private_data = user_axi_dma;//复位skbuffwhile(!skb_queue_empty(&user_axi_dma->s2mm_skbuff)){skb = skb_dequeue(&user_axi_dma->s2mm_skbuff);kfree_skb(skb);}//复位DMA控制器iowrite32(XAXIDMA_CR_RESET_MASK, user_axi_dma->base_addr + 0x00000000 + XAXIDMA_CR_OFFSET);//等待复位完成for(count = 0; count < 200; count++){mm2s_cr = ioread32(user_axi_dma->base_addr + 0x00000000 + XAXIDMA_CR_OFFSET);s2mm_cr = ioread32(user_axi_dma->base_addr + 0x00000030 + XAXIDMA_CR_OFFSET);if(((mm2s_cr & XAXIDMA_CR_RESET_MASK) == 0) && ((s2mm_cr & XAXIDMA_CR_RESET_MASK) == 0))break;msleep_interruptible(1);}if(count >= 200){atomic_inc(&user_axi_dma->open_flag);printk("reset dma failed\r\n");return result;}//注册中断snprintf(user_axi_dma->mm2s_irq_name, sizeof(user_axi_dma->mm2s_irq_name), "axi-dma%ld-mm2s", user_axi_dma->minor);result = request_threaded_irq(user_axi_dma->mm2s_irq, NULL, mm2s_interrupt, irqflags, user_axi_dma->mm2s_irq_name, user_axi_dma);if(result < 0){atomic_inc(&user_axi_dma->open_flag);printk("request mm2s_irq failed\r\n");return result;}snprintf(user_axi_dma->s2mm_irq_name, sizeof(user_axi_dma->s2mm_irq_name), "axi-dma%ld-s2mm", user_axi_dma->minor);result = request_threaded_irq(user_axi_dma->s2mm_irq, NULL, s2mm_interrupt, irqflags, user_axi_dma->s2mm_irq_name, user_axi_dma);if(result < 0){free_irq(user_axi_dma->mm2s_irq, user_axi_dma);atomic_inc(&user_axi_dma->open_flag);printk("request s2mm_irq failed\r\n");return result;}//使能DMA mm2s中断mm2s_cr = ioread32(user_axi_dma->base_addr + 0x00000000 + XAXIDMA_CR_OFFSET);iowrite32(mm2s_cr | XAXIDMA_IRQ_ALL_MASK, user_axi_dma->base_addr + 0x00000000 + XAXIDMA_CR_OFFSET);//使能DMA s2mm中断s2mm_cr = ioread32(user_axi_dma->base_addr + 0x00000030 + XAXIDMA_CR_OFFSET);iowrite32(s2mm_cr | XAXIDMA_IRQ_ALL_MASK, user_axi_dma->base_addr + 0x00000030 + XAXIDMA_CR_OFFSET);//启动DMA接收s2mm_transfer(user_axi_dma, user_axi_dma->s2mm_phy, user_axi_dma->buffer_max);return 0;
}static int user_axi_dma_release(struct inode *inode, struct file *p_file)
{int count;uint32_t mm2s_cr;uint32_t s2mm_cr;struct user_axi_dma *user_axi_dma = p_file->private_data;//复位DMA控制器iowrite32(XAXIDMA_CR_RESET_MASK, user_axi_dma->base_addr + 0x00000000 + XAXIDMA_CR_OFFSET);//等待复位完成for(count = 0; count < 200; count++){mm2s_cr = ioread32(user_axi_dma->base_addr + 0x00000000 + XAXIDMA_CR_OFFSET);s2mm_cr = ioread32(user_axi_dma->base_addr + 0x00000030 + XAXIDMA_CR_OFFSET);if(((mm2s_cr & XAXIDMA_CR_RESET_MASK) == 0) && ((s2mm_cr & XAXIDMA_CR_RESET_MASK) == 0))break;msleep_interruptible(1);}//注销中断free_irq(user_axi_dma->s2mm_irq, user_axi_dma);free_irq(user_axi_dma->mm2s_irq, user_axi_dma);//恢复原子变量的值atomic_set(&user_axi_dma->open_flag, 1);return 0;
}static ssize_t user_axi_dma_read(struct file *p_file, char __user *buf, size_t len, loff_t *pos)
{struct sk_buff *skb;struct user_axi_dma *user_axi_dma = p_file->private_data;if(skb_queue_empty(&user_axi_dma->s2mm_skbuff)){if(p_file->f_flags & O_NONBLOCK)return -EAGAIN;if(wait_event_interruptible(user_axi_dma->s2mm_wq, !skb_queue_empty(&user_axi_dma->s2mm_skbuff)))return -ERESTARTSYS;}skb = skb_dequeue(&user_axi_dma->s2mm_skbuff);if(!skb) {printk("read failed, s2mm_skbuff is empty.\n");return -EAGAIN;}len = (len > skb->len) ? skb->len : len;if(copy_to_user(buf, skb->data, len)){printk("Failed to copy data to user.\n");kfree_skb(skb);return -EFAULT;}kfree_skb(skb);return len;
}static ssize_t user_axi_dma_write(struct file *p_file, const char __user *buf, size_t len, loff_t *pos)
{int result;struct user_axi_dma *user_axi_dma = p_file->private_data;//单次传输不能超过FIFO大小len = (len > user_axi_dma->buffer_max) ? user_axi_dma->buffer_max : len;//将数据拷贝到发送DMA缓冲区if(copy_from_user(user_axi_dma->mm2s_buffer, buf, len) > 0){printk("copy to mm2s_buffer failed\r\n");return -EFAULT;}//复位传输结果user_axi_dma->mm2s_result = 0;//启动DMA接收mm2s_transfer(user_axi_dma, user_axi_dma->mm2s_phy, user_axi_dma->buffer_max);//等待传输完成result = wait_event_interruptible_timeout(user_axi_dma->mm2s_wq, user_axi_dma->mm2s_result, 100);if(result == 0){printk("mm2s_transfer timeout\r\n");return -ETIMEDOUT;}else if(result < 0){printk("mm2s_transfer break\r\n");return result;}return len;
}static unsigned int user_axi_dma_poll(struct file *p_file, poll_table *wait)
{unsigned int mask = 0;struct user_axi_dma *user_axi_dma = p_file->private_data;poll_wait(p_file, &user_axi_dma->s2mm_wq, wait);if (!skb_queue_empty(&user_axi_dma->s2mm_skbuff))mask |= POLLIN | POLLRDNORM;return mask;
}static long user_axi_dma_ioctl(struct file *p_file, unsigned int cmd, unsigned long arg)
{struct user_axi_dma *user_axi_dma = p_file->private_data;return 0;
}static const struct file_operations user_axi_dma_fops = {.owner = THIS_MODULE,.open = user_axi_dma_open,.release = user_axi_dma_release,.read = user_axi_dma_read,.write = user_axi_dma_write,.poll = user_axi_dma_poll,.unlocked_ioctl = user_axi_dma_ioctl,
};//设备和驱动匹配成功执行
static int user_axi_dma_probe(struct platform_device *pdev)
{int result;struct device *device;struct user_axi_dma *user_axi_dma;char device_driver_name[128];printk("%s\r\n", __FUNCTION__);//设置SPI设备的DMA寻址范围,不然dma_alloc会执行失败pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);//分配设备句柄,采用devm_xxx函数申请资源,后续可自动释放user_axi_dma = devm_kzalloc(&pdev->dev, sizeof(struct user_axi_dma), GFP_KERNEL);if (!user_axi_dma){printk("alloc memory failed\r\n");return -ENOMEM;}memset(user_axi_dma, 0, sizeof(struct user_axi_dma));//设置原子变量为1,表示未执行open操作atomic_set(&user_axi_dma->open_flag, 1);//初始化等待队列user_axi_dma->mm2s_result = 0;init_waitqueue_head(&user_axi_dma->mm2s_wq);init_waitqueue_head(&user_axi_dma->s2mm_wq);//初始化skbuffskb_queue_head_init(&user_axi_dma->s2mm_skbuff);//获取缓冲区最大大小result = of_property_read_u32_index(pdev->dev.of_node, "buffer-max", 0, &user_axi_dma->buffer_max);if(result < 0){printk("get \"buffer-max\" parameter failed\r\n");return result;}//分配mm2s_buffer缓冲帧user_axi_dma->mm2s_buffer = dma_alloc_wc(&pdev->dev, user_axi_dma->buffer_max, &user_axi_dma->mm2s_phy, GFP_KERNEL);if(!user_axi_dma->mm2s_buffer){printk("alloc mm2s_buffer failed\r\n");return -ENOMEM;}memset(user_axi_dma->mm2s_buffer, 0x00, user_axi_dma->buffer_max);//分配s2mm_buffer缓冲帧user_axi_dma->s2mm_buffer = dma_alloc_wc(&pdev->dev, user_axi_dma->buffer_max, &user_axi_dma->s2mm_phy, GFP_KERNEL);if(!user_axi_dma->s2mm_buffer){dma_free_wc(&pdev->dev, user_axi_dma->buffer_max, user_axi_dma->mm2s_buffer, user_axi_dma->mm2s_phy);printk("alloc s2mm_buffer failed\r\n");return -ENOMEM;}memset(user_axi_dma->s2mm_buffer, 0x00, user_axi_dma->buffer_max);//映射寄存器资源user_axi_dma->base_addr = devm_platform_ioremap_resource(pdev, 0);if (IS_ERR(user_axi_dma->base_addr)){dma_free_wc(&pdev->dev, user_axi_dma->buffer_max, user_axi_dma->s2mm_buffer, user_axi_dma->s2mm_phy);dma_free_wc(&pdev->dev, user_axi_dma->buffer_max, user_axi_dma->mm2s_buffer, user_axi_dma->mm2s_phy);printk("ioremap reg failed.\n");return PTR_ERR(user_axi_dma->base_addr);}//获取中断号user_axi_dma->mm2s_irq = of_irq_get(pdev->dev.of_node, 0);if(user_axi_dma->mm2s_irq <= 0){dma_free_wc(&pdev->dev, user_axi_dma->buffer_max, user_axi_dma->s2mm_buffer, user_axi_dma->s2mm_phy);dma_free_wc(&pdev->dev, user_axi_dma->buffer_max, user_axi_dma->mm2s_buffer, user_axi_dma->mm2s_phy);printk("irq mm2s_irq failed");return user_axi_dma->mm2s_irq;}printk("mm2s_irq:%d\r\n", user_axi_dma->mm2s_irq);user_axi_dma->s2mm_irq = of_irq_get(pdev->dev.of_node, 1);if(user_axi_dma->s2mm_irq <= 0){dma_free_wc(&pdev->dev, user_axi_dma->buffer_max, user_axi_dma->s2mm_buffer, user_axi_dma->s2mm_phy);dma_free_wc(&pdev->dev, user_axi_dma->buffer_max, user_axi_dma->mm2s_buffer, user_axi_dma->mm2s_phy);printk("irq s2mm_irq failed");return user_axi_dma->s2mm_irq;}printk("s2mm_irq:%d\r\n", user_axi_dma->s2mm_irq);//分配设备IDresult = ida_simple_get(&user_axi_dma_ida, 0, USER_AXI_DMA_MAX_MINORS, GFP_KERNEL);if(result < 0){dma_free_wc(&pdev->dev, user_axi_dma->buffer_max, user_axi_dma->s2mm_buffer, user_axi_dma->s2mm_phy);dma_free_wc(&pdev->dev, user_axi_dma->buffer_max, user_axi_dma->mm2s_buffer, user_axi_dma->mm2s_phy);printk("Not able to get minor id for device.\n");return result;}//合成设备号user_axi_dma->minor = result;user_axi_dma->devt = MKDEV(MAJOR(user_axi_dma_major), user_axi_dma->minor);//初始化CDEV对象cdev_init(&user_axi_dma->cdev, &user_axi_dma_fops);user_axi_dma->cdev.owner = THIS_MODULE;//向系统添加CDEV对象result = cdev_add(&user_axi_dma->cdev, user_axi_dma->devt, 1);if(result < 0){ida_simple_remove(&user_axi_dma_ida, user_axi_dma->minor);dma_free_wc(&pdev->dev, user_axi_dma->buffer_max, user_axi_dma->s2mm_buffer, user_axi_dma->s2mm_phy);dma_free_wc(&pdev->dev, user_axi_dma->buffer_max, user_axi_dma->mm2s_buffer, user_axi_dma->mm2s_phy);printk("chardev registration failed.\n");return result;}printk("device major %d, device minor %d, device file name = user_axi_dma%ld\r\n",MAJOR(user_axi_dma->devt), MINOR(user_axi_dma->devt), user_axi_dma->minor);//创建设备文件snprintf(device_driver_name, sizeof(device_driver_name), "user_axi_dma%ld", user_axi_dma->minor);device = device_create(user_axi_dma_class, NULL, user_axi_dma->devt, NULL, device_driver_name);if(IS_ERR(device)){cdev_del(&user_axi_dma->cdev);ida_simple_remove(&user_axi_dma_ida, user_axi_dma->minor);dma_free_wc(&pdev->dev, user_axi_dma->buffer_max, user_axi_dma->s2mm_buffer, user_axi_dma->s2mm_phy);dma_free_wc(&pdev->dev, user_axi_dma->buffer_max, user_axi_dma->mm2s_buffer, user_axi_dma->mm2s_phy);printk("device create failed");return PTR_ERR(device);}//设置平台设备的驱动私有数据dev_set_drvdata(&pdev->dev, user_axi_dma);return 0;
}//设备或驱动卸载时执行
static int user_axi_dma_remove(struct platform_device *pdev)
{struct sk_buff *skb;struct user_axi_dma *user_axi_dma = dev_get_drvdata(&pdev->dev);printk("%s\r\n", __FUNCTION__);if(!user_axi_dma)return 0;//删除设备文件device_destroy(user_axi_dma_class, user_axi_dma->devt);//从内核删除cdev对象cdev_del(&user_axi_dma->cdev);//释放设备IDida_simple_remove(&user_axi_dma_ida, user_axi_dma->minor);//释放DMA缓冲区dma_free_wc(&pdev->dev, user_axi_dma->buffer_max, user_axi_dma->s2mm_buffer, user_axi_dma->s2mm_phy);dma_free_wc(&pdev->dev, user_axi_dma->buffer_max, user_axi_dma->mm2s_buffer, user_axi_dma->mm2s_phy);//复位skbuffwhile(!skb_queue_empty(&user_axi_dma->s2mm_skbuff)){skb = skb_dequeue(&user_axi_dma->s2mm_skbuff);kfree_skb(skb);}return 0;
}//匹配列表,用于设备树和平台驱动匹配
static const struct of_device_id user_axi_dma_of_match[] = {{ .compatible = "user_axi_dma" },{ /* Sentinel */ }
};
//平台驱动
struct platform_driver user_axi_dma_drv = {.driver = {.name = "user_axi_dma",							//平台驱动名称.owner = THIS_MODULE,.pm = NULL,.of_match_table = user_axi_dma_of_match,},.probe = user_axi_dma_probe,				//设备和驱动匹配成功执行.remove = user_axi_dma_remove,				//设备或驱动卸载时执行
};static int __init plt_drv_init(void)
{int result;printk("%s\r\n", __FUNCTION__);//根据次设备号起始值动态注册字符设备号result = alloc_chrdev_region(&user_axi_dma_major, 0, USER_AXI_DMA_MAX_MINORS, "char-driver-template");if(result < 0){printk("alloc chrdev failed\r\n");return result;}printk("first device major %d, minor %d\r\n", MAJOR(user_axi_dma_major), MINOR(user_axi_dma_major));//创建class对象user_axi_dma_class = class_create(THIS_MODULE, "led,class");if(IS_ERR(user_axi_dma_class)){unregister_chrdev_region(user_axi_dma_major, USER_AXI_DMA_MAX_MINORS);printk("class create failed");return PTR_ERR(user_axi_dma_class);}//注册平台驱动result = platform_driver_register(&user_axi_dma_drv);if(result < 0){class_destroy(user_axi_dma_class);unregister_chrdev_region(user_axi_dma_major, USER_AXI_DMA_MAX_MINORS);printk("add cdev failed\r\n");return result;}return 0;
}static void __exit plt_drv_exit(void)
{printk("%s\r\n", __FUNCTION__);//注销平台驱动platform_driver_unregister(&user_axi_dma_drv);//销毁class对象class_destroy(user_axi_dma_class);//注销字符设备号unregister_chrdev_region(user_axi_dma_major, USER_AXI_DMA_MAX_MINORS);
}module_init(plt_drv_init);
module_exit(plt_drv_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("csdn");
MODULE_DESCRIPTION("axi_dma_driver");

AXI DMA驱动测试程序

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <pthread.h>static int amp_fd;static uint8_t wbuffer[512];
static uint8_t rbuffer[512*2];
static volatile ssize_t read_total = 0, write_total = 0;
static volatile int cnt = 0;void *echo_thread(void *arg)
{int32_t result;ssize_t write_size, read_size;int32_t magic = 0;while(1){//填充数据magic++;for(int i=0; i<sizeof(wbuffer); i++)wbuffer[i] = (uint8_t)(magic + i);//发送数据result = write(amp_fd, wbuffer, sizeof(wbuffer));if(result != sizeof(wbuffer)){printf("write failed\r\n");continue;}write_size = result;write_total += write_size;//读取数据memset(rbuffer, 0,  sizeof(rbuffer));result = read(amp_fd, rbuffer, sizeof(rbuffer));if(result != write_size){printf("read failed\r\n");continue;}read_size = result;read_total += read_size;//校验数据是否一致for(int i=0; i<sizeof(wbuffer); i++){if(wbuffer[i] != rbuffer[i]){printf("check out failed\r\n");break;}}cnt++;}
}int main(int argc, char *argv[])
{int err;pthread_t thread;char *rpmsg_dev="/dev/rpmsg0";if(argc > 1)rpmsg_dev = argv[1];printf("amp test\r\n");amp_fd = open(rpmsg_dev, O_RDWR);if(amp_fd < 0){perror("error");return -1;}err = pthread_create(&thread, NULL, echo_thread, NULL);if(err != 0){printf("create thread failed, error code %d\r\n", err);return -1;}err = pthread_detach(thread);if(err != 0){printf("thread detach failed, error code %d\r\n", err);return -1;}while(1){sleep(1);printf("read speed = %fMB/s\r\n", read_total/1.0f/1024.0f/1024.0f);read_total = 0;printf("write speed = %fMB/s\r\n", write_total/1.0f/1024.0f/1024.0f);write_total = 0;printf("echo count = %d\r\n", cnt);cnt = 0;}
}

文章转载自:
http://clergyman.c7630.cn
http://pseudocholinesterase.c7630.cn
http://seeable.c7630.cn
http://nidicolous.c7630.cn
http://poleaxe.c7630.cn
http://camoufleur.c7630.cn
http://parramatta.c7630.cn
http://absolutist.c7630.cn
http://gemination.c7630.cn
http://refractable.c7630.cn
http://jin.c7630.cn
http://endometria.c7630.cn
http://tuning.c7630.cn
http://cookroom.c7630.cn
http://refasten.c7630.cn
http://krans.c7630.cn
http://outbuilding.c7630.cn
http://shiite.c7630.cn
http://injectable.c7630.cn
http://irresistibility.c7630.cn
http://foliolate.c7630.cn
http://lipidic.c7630.cn
http://cholecystography.c7630.cn
http://pinxit.c7630.cn
http://horntail.c7630.cn
http://autotelegraph.c7630.cn
http://friable.c7630.cn
http://oland.c7630.cn
http://devolutionist.c7630.cn
http://gypsy.c7630.cn
http://shoeshop.c7630.cn
http://turk.c7630.cn
http://rebranch.c7630.cn
http://acculturize.c7630.cn
http://advowson.c7630.cn
http://inglenook.c7630.cn
http://curtis.c7630.cn
http://intoed.c7630.cn
http://hypolydian.c7630.cn
http://aphthong.c7630.cn
http://zonular.c7630.cn
http://tribal.c7630.cn
http://lyons.c7630.cn
http://wish.c7630.cn
http://bretagne.c7630.cn
http://breeding.c7630.cn
http://ideomotor.c7630.cn
http://monadism.c7630.cn
http://morphiomaniac.c7630.cn
http://primp.c7630.cn
http://molluscoidal.c7630.cn
http://iconostasis.c7630.cn
http://mustachio.c7630.cn
http://patio.c7630.cn
http://centrosphere.c7630.cn
http://serfhood.c7630.cn
http://interfile.c7630.cn
http://caac.c7630.cn
http://gemma.c7630.cn
http://microvolt.c7630.cn
http://skimboard.c7630.cn
http://shoon.c7630.cn
http://matilda.c7630.cn
http://broadish.c7630.cn
http://sessional.c7630.cn
http://hincty.c7630.cn
http://citizenship.c7630.cn
http://scandalmonger.c7630.cn
http://fairly.c7630.cn
http://caesarean.c7630.cn
http://worshiper.c7630.cn
http://technologist.c7630.cn
http://scottie.c7630.cn
http://kohl.c7630.cn
http://declutch.c7630.cn
http://psro.c7630.cn
http://tannate.c7630.cn
http://megabyte.c7630.cn
http://urology.c7630.cn
http://deave.c7630.cn
http://hochheimer.c7630.cn
http://connive.c7630.cn
http://degras.c7630.cn
http://dactyloscopy.c7630.cn
http://dorothy.c7630.cn
http://renunciatory.c7630.cn
http://bfa.c7630.cn
http://boz.c7630.cn
http://boogeyman.c7630.cn
http://penghu.c7630.cn
http://ado.c7630.cn
http://parget.c7630.cn
http://porphyrize.c7630.cn
http://cabalistic.c7630.cn
http://cellulated.c7630.cn
http://epicuticle.c7630.cn
http://unadvantageous.c7630.cn
http://neumes.c7630.cn
http://slop.c7630.cn
http://disgorge.c7630.cn
http://www.zhongyajixie.com/news/85068.html

相关文章:

  • 东莞品牌网站建设重庆网站建设与制作
  • 作风建设主题活动 网站便宜的seo官网优化
  • 沈阳市网站建设公司广州seo
  • 嘉兴市做外贸网站新闻头条今日要闻国内新闻最新
  • 宁晋网站建设设计中国目前最好的搜索引擎
  • wordpress程序安装seo网站技术培训
  • 备案 网站首页url怎么推广自己的网站
  • 网站首页开发收费自媒体平台app下载
  • 做网站一般用什么几号字制作网页完整步骤代码
  • 做软件网站品牌策划公司排名
  • 单页面网站制作视频广西seo优化
  • 网站开发专业培训怎么自己做一个网站平台
  • 餐饮网站建设方案深圳市企业网站seo营销工具
  • 做网站主机选择seo 是什么
  • 徐汇专业做网站整合营销传播成功案例
  • 国内做卷学习网站一句简短走心文案
  • 常州外贸建站线上宣传的方式
  • 宁波网站制作怎样百度百家号
  • 网站建设费怎么做会计分录惠州网站制作推广
  • 如果域名网站用来做违法青岛今天发生的重大新闻
  • 专业苏州网站建设南通网络推广
  • 开发网站商城百度统计平台
  • wordpress模板是否死循环桌子seo关键词
  • 海外医疗手机网站建设外链发布网站
  • 淘宝店铺装修免费全套模板夫唯seo教程
  • 可拖拽 网站建设好省推广100种方法
  • 论吉林省网站职能建设免费网站服务器安全软件下载
  • roseonly企业网站优化直接下载app
  • 厦门博客网站制作国内新闻最新消息简短
  • 自己做衣服的网站石家庄关键词排名首页