linux驱动学习记录(三)-PCI IO读写、中断、DMA传输
发布日期:2021-10-10 05:30:58 浏览次数:21 分类:技术文章

本文共 3026 字,大约阅读时间需要 10 分钟。

实现方法不止本文这些,本文只是作者对自己成功实现的方法记录

1.  PCI IO内存读写

 

 I/O端口是驱动程序与许多设备之间的通信方式,Linux的内核为我们提供了I/O端口分配的操作接口,但对PCI设备来讲,它的配置地址空间已经为其指定了I/O端口范围,不需要额外的分配操作。

下列代码通过访问I/O内存实现访问设备内存。

unsigned long mmio_start, addr1, addr2;

void __iomem *ioaddr;
mmio_start = pci_resource_start( pdev, 1);//获取bar1的首地址

ioaddr = pci_iomap(pdev, 1, 0);  //内核对PCI bar1 内存映射的地址

addr1 = ioread32( ioaddr );
addr2 = ioread32( ioaddr + 4 );
printk(KERN_INFO "mmio start: %lX\n", mmio_start);
printk(KERN_INFO "ioaddr: %p\n", ioaddr);

 

 

2.  中断

 

2.1   申请中断与释放中断

 

在设备文件打开(即进入file_operationsopen 成员函数)时,使用request_irq函数向内核申请中断

int request_irq(unsigned int irq,

irq_handler_t handler,

unsigned long flags,

const char *name, void *dev);

irq是要申请的硬件中断号。

handler是向系统登记的中断处理函数(顶半部),是一个回调函数,中断发生时,系统调用这个函数,dev参数将被传递给它。

irqflags是中断处理的属性,可以指定中断的触发方式以及处理方式。在触发方式方面,可以是IRQF_TRIGGER_RISING、 IRQF_TRIGGER_FALLING、 IRQF_TRIGGER_HIGH、 IRQF_TRIGGER_LOW等。在处理方式方面,若设置了IRQF_SHARED,则表示多个设备共享中断,dev是要传递给中断服务程序的私有数据,一般设置为这个设备的设备结构体或者NULL。

 

在设备文件关闭(即进入file_operationsrelease 成员函数)时,使用free_irq函数释放中断

void free_irq(unsigned int irq,void *dev_id);

 

2.2   linux中断处理机制

为了在中断执行时间尽量短和中断处理需完成的工作尽量大之间找到一个平衡点,Linux将中断处理程序分解为两个半部:顶半部(Top Half)和底半部(Bottom Half)。

Linux实现底半部的机制主要有tasklet、工作队列、软中断和线程化irq。

 

进入中断服务程序后有三步操作

1. 根据硬件协议读取中断状态位,利用掩码判断是否为本设备的中断,如果不是本设备中断则返回IRQ_NONE。

2. 清除中断标志。

3. 完成中断要处理的工作(如果工作量大,应该将耗时的工作交给底半部工作队列,尽快退出中断服务程序),返回IRQ_HANDLED,告知内核该中断已被处理。

 

下列为使用tasklet作为底半部处理中断的示例代码

/*中断处理底半部*/void xxx_do_tasklet(unsigned long){     ...}/* 定义tasklet和底半部函数并将它们关联 */DECLARE_TASKLET(xxx_tasklet, xxx_do_tasklet, 0);/*中断处理顶半部*/irqreturn_t xxx_interrupt(int irq, void *dev_id){     //读取状态位     unsigned long int_status = ioread32(bar_base[0] + 8);     //利用掩码判断是否为本设备的中断	if(!(int_status & 0x3))	{		return IRQ_NONE;	}     //清除中断标志     iowrite32(0xff00, bar_base[0] + 0);     //调度tasklet     tasklet_schedule(&xxx_tasklet);     return IRQ_HANDLED;}/* 字符设备file_operations open 成员函数 */static int xxx_open(struct inode *inode, struct file *filp){     ...	//申请中断,注册中断服务程序	if(request_irq(irq, xxx_interrupt, IRQF_SHARED, PCI_NAME, lspci_devp))	{		printk("==========>>request_irq error\n");	}     ...}/* 字符设备file_operations release 成员函数 */static int xxx_release(struct inode *inode, struct file *filp){	...	//释放中断	free_irq(irq, lspci_devp);	...}

3.  DMA传输

DMA本身不属于一种等同于字符设备、块设备和网络设备的外设,它只是一种外设与内存交互数据的方式。

驱动要做的是在内核空间中申请内存,往内存中写入数据(或者是等DMA传输结束后读出数据,取决于数据传输的方向),将这块内存映射为物理地址,把地址发送给设备并告知设备DMA传输准备工作已完成。

内核空间中申请内存可以使用kmalloc()函数

void *kmalloc(size_t size, int flags);

给kmalloc()的第一个参数是要分配的块的大小;第二个参数为分配标志,用于控制kmalloc()的行为。最常用的分配标志是GFP_KERNEL,其含义是在内核空间的进程中申请内存。使用kfree()函数将内存释放。

 

 

对于单个已经分配的缓冲区而言,使用dma_map_single()可实现流式DMA映射,该函数原型为:

dma_addr_t dma_map_single(struct device *dev, void *buffer, size_t size,

enum dma_data_direction direction);

如果映射成功,返回的是总线地址,否则,返回NULL。第4个参数为DMA的方向,可能的值包括

DMA_TO_DEVICE、DMA_FROM_DEVICE、DMA_BIDIRECTIONAL和DMA_NONE。

dma_map_single()的反函数为dma_unmap_single(),原型是:

void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,

enum dma_data_direction direction);

 

最后将总线地址写入到硬件寄存器中,具体逻辑实现须和硬件工程师进行沟通。

转载地址:https://blog.csdn.net/qq_22042587/article/details/78175648 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:windows上cmake与nmake的搭配用法
下一篇:linux驱动学习记录(二)-PCI驱动框架

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2024年03月20日 03时59分54秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

稳定币usda是哪个发行的_武夷山币装帧款曝光,共4款设计,你喜欢哪款? 2019-04-21
可变车道怎么走不违章_走ETC竟比人工车道贵50%!交警:这3点不知道,吃亏的是自己... 2019-04-21
苹果笔记本的end键_笔记本用户的大烦恼:触控板,想好好用你不容易 2019-04-21
趣玩机器人什么时候成立的_【直播回顾】当我们谈机器人集成调试的时候在谈什么... 2019-04-21
中考大数据大连79_中考大数据 | 大连部分初中2019年中考指标生录取最低分及人数统计!... 2019-04-21
vue 地理位置定位_HTML5地理位置 2019-04-21
pac代理模式什么意思_托管仓库租赁电商仓储运营模式托管什么意思 2019-04-21
validated 验证数组_在 Laravel 中处理请求验证的智能方法 2019-04-21
洞泾智能机器人产业基地_G60科创走廊洞泾人工智能产业基地(核心区块)暨洞泾镇招商人员培训班顺利开班... 2019-04-21
java 拼接路径优雅方式_Java安全编码实践总结 2019-04-21
realme x2 深度测试打不开_搭载65W超级闪充,realme真我X7手机充电评测 2019-04-21
整数取反编程_【每日编程185期】数字的补数 2019-04-21
能用别的软件吗_手机软件能用蓝牙传送吗 2019-04-21
为什么图片要2的倍数_为什么宝宝喜欢流“口水”?这种2种原因父母要知道,建议收藏... 2019-04-21
下载了XAMPP怎样打开MYSQL_xampp mysql安装启动 2019-04-21
pdo转mysql_mysql转mysqli或pdo 2019-04-21
mysql如果没有表就创建_mysql – 改变表是否存在或创建如果没有 2019-04-21
ireport连接mysql_ireport 4.5教程之数据源介绍 2019-04-21
mysql多维模型_数据仓库数据库设计方法---关系模型和多维模型比较分析 2019-04-21
局域网聊天程序 java MySQL_java 基于TCP/IP协议的局域网聊天小程序 2019-04-21