Linux中断——request_irq
目录
目录
linux 中断之irq
前言
中断注册与释放
第一个参数:irq相关
查看/proc/interrupts
查看/proc/stat
Probe IRQ Number问题
第二个参数:Handler相关
第三个参数:flag相关
第四个参数:dev_name
第五个参数:dev_id
linux 中断之irq
关键字:中断号、共享中断、dev_id、proc文件系统、中断处理函数、中断标识、tasklet、workqueue
前言
前面一篇文章已经对中断做了一些简单介绍《关于Linux中断一些思考》,但是中断是怎么告诉内核(kernel)的呢?这里我们带着问题去了解一下irq的调用。
所谓中断它其实是硬件产生了一个信号,然后告诉内核要去处理它。Linux处理中断很像用户空间(user space)处理信号(signal)一样,内核启动的时候注册了这个中断之后,当中断产生的时候(由硬件触发)就会调用对应的中断处理函数。这里需要注意在中断处理的时候要考虑公共资源的竞态和并发问题(这个后续文章会单独介绍)
在介绍中断注册前,先了解一下中断线(interrupt lines),像IO资源一样,系统的中断线也是非常有限和宝贵的资源,所以会出现多个模块共享一个中断线的情况。模块在使用中断线前必须先注册它,而且用完之后必须释放它(不然在共享同一个中断的模块无法使用这个中断)。
中断注册与释放
int request_irq(unsigned int irq,irqreturn_t (*handler)(int, void *, struct pt_regs *),unsigned long flags, const char *dev_name,void *dev_id);void free_irq(unsigned int irq, void *dev_id);
说明:返回值,成功为0,失败负值,-EBUSY表示一个驱动正在使用这个中断线(不常见);
unsigned int irq:请求的中断号,这个是系统预先设定好的,可以在irq.h中找到对应值;
irqreturn_t (*handler) (int ,void *, struct pt_regs *):中断处理函数指针;
unsigned long flags:中断标志位,可以是一个或者多个,它跟中断处理相关;
const char *dev_name:中断名称,这个可以在系统运行后查看/proc/interrupts找到对应名称
void *dev_id:主要用在共享型中断线中,它一般指向对应驱动的私有数据,以便中断释放的时候,只释放指定驱动中的中断,它具有唯一性;当它不是共享型的时候,可以设定为NULL,但是建议将它指向设备结构体;
提示:中断处理的安装可以在驱动模块的初始化中,也可以在设备被打开使用的过程中。通常建议在设备打开使用的时候执行中断处理的请求,因为系统中的中断号本来就有限。当一个模块在初始化的时候请求IRQ,它将会阻止其他任何驱动使用这个中断,即使这个中断没有被用到。而在打开设备的时候请求中断,将会把资源极大利用起来。
所以最佳调用request_irq的位置是设备被打开的时候,而最佳关闭中断free_irq的时候是最后关闭设备的时候。但是这个也不是绝对的,针对一些短的请求,可以将它放到初始化函数中。
第一个参数:irq相关
如果想要查看相关中断的一些状态或者使用情况怎么办?Linux在proc系统中提供了两个文件供查看。
查看/proc/interrupts
cat /proc/interruptsCPU0 CPU1
0: 4848108 34 IO-APIC-edge timer
2: 0 0 XT-PIC cascade
8: 3 1 IO-APIC-edge rtc
10: 4335 1 IO-APIC-level aic7xxx
11: 8903 0 IO-APIC-level uhci_hcd
12: 49 1 IO-APIC-edge i8042
NMI: 0 0
LOC: 4848187 4848186
ERR: 0
MIS: 0
其中第一列是IRQ 号,可以看到有些中断号没有显示出来,这代表它在当前执行cat这个时间点没有被用到;通常中断处理在第一个CPU中,这是为了最大限度利用缓存;最后两列中断控制器和中断名(上面提到的dev_name);中间的CPU列代表中断调用次数;
查看/proc/stat
通过/proc/interrupts可以查看当前运行中的中断信息,但是如果中断退出后要查看它的历史使用情况怎么办呢?这里可以通过/proc/stat来查看,用cat会看到它有很多行输出,这里我们只关注intr行
intr 5167833 5154006 2 0 2 4907 0 2 68 4 0 4406 9291 50 0 0
其中第一个数字表示所有的中断调用统计总数5167833次,后面依次是中断号为0,1,2,3...,从这里看看到从系统启动到执行当前命令后所有中断被调用的次数以及总和。
Probe IRQ Number问题
为什么提出自动探测interrupt number问题?因为有时候用户的关注点不在interrupt number而在他想让硬件产生中断并处理它,也就说并不关注你是什么中断,只要能作用就行了。但是也不能随便给一个中断号就草草了事,不然就会有1、中断号出现驴唇不对马嘴,后续看代码的人异常痛苦;2、中断冲突,本来这个这个中断号是某一个中断专属的,结果被你抢去用了,这样会导致一系列问题。所以针对这种不关心具体中断号意义的用户,内核提供了一个probe 接口。
- 自动处理
内核自带api:
unsigned long probe_irq_on(void);int probe_irq_off(unsigned long);
第一个probe_irq_on函数,输入参数为void,返回一个unsigned long 中断号。以下是根据端口地址来自动分配中断号的代码片段,这块代码会跟具体的平台相关。
if (short_irq < 0) /* not yet specified: force the default on */switch(short_base) {case 0x378: short_irq = 7; break;case 0x278: short_irq = 2; break;case 0x3bc: short_irq = 5; break;
}
- 加载时指定
除了自动侦测还有一种是,在模块加载的时候指定它,这种方式非常灵活,适用于调试阶段。
insmod ./short.ko irq=x
第二个参数:Handler相关
request_irq的第二个参数是中断处理函数,也就是中断发生之后,要执行的代码。先介绍这个函数
irqreturn_t (*handler)(int irq, void *dev_id, struct pt_regs *pt_regs)
输入参数:
第一个参数irq就是中断号;
第二个参数dev_id通用指针在irq_flag为shared的时候发挥作用,因为在共享中断号在中断处理do_IRQ中,需要区分具体是哪个中断,然后处理对应的中断。(打个比方,中断号irq对应具体的班级,dev_id对应班级里面的哪个学生学号,就像学校广播找人,先说哪个班--irq,然后说哪个学生--dev_id);
第三个参数pt_regs,主要用来记录CPU进入中断前保存CPU的上下文,仅做调试和监视作用,实际中断中使用非常少;
返回值:
enum irqreturn{IRQ_NONE, //中断处理程序检测到一个中断,但该中断对应的设备并不是在注册处理函数期间指定的产生源时,返回这个IRQ_HANDLED,//中断处理程序被正确调用且确实时它对应的设备产生了中断,返回这个IRQ_WAKE_THREAD,};
如果在执行过程中想disable某一个或所有中断,又或者enable某一个或所有中断呢?Linux内核也为我们提供了对应的接口。
- 某一个中断
void disable_irq(int irq);
void disable_irq_nosync(int irq);
void enable_irq(int irq);
这里输入参数都是irq,就是指定要disable或enable的中断号。这里着重介绍disable_irq和disable_irq_nosync这两个差异,从nosync这个字面意思可以看到它是简单粗暴的方式返回。事实上,disable_irq是既disable指定的中断也会等待当前正在处理的中断(这里要注意,如果执行这个api的线程用到了handler里面用到的一些资源,比如spinlock,它会导致系统死锁);disable_irq_nosync会快速返回,但是它可能会导致系统产生竞态问题(由于它处理简单粗暴,如果handle里面有一些公共资源没有释放,其他进程再用就会拿不到资源)
- 所有中断
void local_irq_save(unsigned long flags);
void local_irq_disable(void);void local_irq_restore(unsigned long flags);
void local_irq_enable(void);
在disable所有中断之前先保存当前中断的状态给一个flags,这里有人可能会想,这里为什么不是一个指针类型?通过阅读local_irq_save的实现发现它是一个define形式,也就是说它就是赋值给这个flag。建议读者可以看看源码/linux/include/linux/irqflags.h,这样会有一个比较深刻的认识。
那既然熟悉了handle,是不是我们可以随心所欲的在handle写自己想要的代码?情况并非如此,handle函数是有限制的。
Handle的使用注意事项:
- 不可以和用户空间传递数据--因为传动动作不是在处理的上下文中执行的;
- 不允许执行sleep操作,比如wait_event、内存分配、锁定一个semaphore;
- 不允许任务调度
总之,耗时、pending的操作不能在handle中使用,handle中的操作要少、快;如果有耗时或者pending的操作,建议使用tasklet和workqueue,这部分属于中断Bottom half,后续文章单独介绍它怎么使用。简单说明两者注意事项,tasklet也是执行比较快的操作,而且属于原子操作型;workqueue可以用于延时性要求比较高的操作,不必追求原子性,但是依然不能用于跟用户空间的数据拷贝动作,因为他们不在同一个处理上下文中。
第三个参数:flag相关
IRQF_DISABLED:如果被指定它,那么它会禁用其他所有中断,如果不设定,程序可以和其他中断程序同时运行;
IRQF_TIMER:为系统的定时器中断而准备的。
IRQF_SHARED:表示多个中断处理程序可以共享中断号,即如果没有设定只有一个中断程序使用这个中断号,如果设定了,多个中断程序可以共享这个中断号。
第四个参数:dev_name
可以根据自定义来,在上面介绍/proc/interrupts中可以看到它。
第五个参数:dev_id
前面也已经做了相关介绍,主要是用在共享中断中,在执行中断do_IRQ中识别身份的唯一标识,方便找到指定的handle,也方便在enable、disable、free等操作中找到指定的中断,并对它进行相关处理。
Linux中断——request_irq相关推荐
- Linux中断子系统---中断申请request_irq()与中断线程化request_threaded_irq()
一.申请中断request_irq() Linux中使用中断需要先进行申请,申请中断的API函数如下: int request_irq(unsigned int irq,irq_handler_t h ...
- 探测函数 中断 linux,linux中断编程函数
总结下linux中断编程的函数,方便下次使用时查看. 1.中断申请和释放 int request_irq( unsigned int irq, irq_handler_t handler, unsig ...
- Linux 中断之中断处理浅析
1. 中断的概念 中断是指在CPU正常运行期间,由于内外部事件或由程序预先安排的事件引起的 CPU 暂时停止正在运行的程序,转而为该内部或外部事件或预先安排的事件服务的程序中去,服务完毕后再返回去继续 ...
- arm Linux 中断管理机制
关键词:GIC.IAR.EOI.SGI/PPI/SPI.中断映射.中断异常向量.中断上下文.内核中断线程.中断注册. 1.1 ARM支持中断类型 ARM GIC-v2支持三种类型的中断: SGI:软件 ...
- linux中断的上半部和下半部
原文地址:linux中断的上半部和下半部 作者:td1442911376 http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=246 ...
- Linux 中断实验
目录 Linux 中断简介 Linux 中断API 函数 上半部与下半部 设备树中断信息节点 获取中断号 硬件原理图分析 实验程序编写 修改设备树文件 按键中断驱动程序编写 编写测试APP 运行测试 ...
- Linux中断子系统-通用框架处理
背景 Kernel版本:4.14 ARM64处理器,Contex-A53,双核 使用工具:Source Insight 3.5, Visio 1. 概述 <Linux中断子系统(一)-中断控制器 ...
- (九)linux中断编程
目录 (一)linux中断的介绍 (二)内核中断的操作过程 (三)实例代码 (一)linux中断的介绍 linux内核中的中断通过中断子系统来管理.linux系统中有专门的中断子系统,原理很复杂,驱动 ...
- Linux 中断所有知识点
目录 Linux 中断管理机制 GIC 硬件原理 GIC v3中断类别 GIC v3 组成 中断路由 中断状态机 中断处理流程 GIC 驱动 设备树 初始化 中断的映射 数据结构 中断控制器注册 ir ...
最新文章
- LeetCode 829. Consecutive Numbers Sum--笔试题--C++解法
- 【转载】混合高斯模型(Mixtures of Gaussians)和EM算法
- hdu4994 博弈,按顺序拿球
- HASH 大量插入与查询
- liferay 在css 中,引入图片的写法
- php mail 在线,在线web e-mail发送
- camelcase_在Python中将字符串转换为camelCase
- 专访蒋彪:JavaEE是企业级开发首选
- erlang之三种socket消息循环
- es6 Map,Set 和 WeakMap,WeakSet
- ROS系列书籍--机械工业出版社
- mysql安装出现change_mysql-5.msi安装出现change,repaire,or remove installation
- mysql上线脚本规范_专业规范的mysql启停脚本
- 什么是flex布局,它的常用属性有哪些
- mysql数据库基础:存储过程和函数
- 理财入门书-小狗钱钱 -读书笔记
- 华为freebudspro2和freebudspro区别
- 打开Windows任务管理器的七种方法
- Java打印乘法口诀表(任何数)
- Kotlin第五章: android网络编程
热门文章
- 不写代码建博客!在浏览器完成博客搭建,有超详细文档,小白轻松搞定
- R6034问题的解决
- 计算机睡眠后黑屏,电脑睡眠唤醒后一直是黑屏状态怎么办?
- http://cn.bing.com/ 微软的搜索引擎“bing 必应” 终于开通了……
- 豆瓣的架构—专访豆瓣网站的技术总监洪强宁
- Java毕业设计_基于javaEE的论坛的设计和实现
- STM32F10xxx20xxx21xxxL1xxxx Cortex-M3程序设计手册 阅读笔记四(5):系统滴答定时器
- 《数字图像处理 MATLAB版》学习笔记
- Aspose.PDF 23.1.0 for .NET Crack
- JetBrains-License-Server