在 2.4 内核和 2.6内核中都使用

request_irq() 函数来注册中断服务函数。在 2.4 内核中,需要包含的头文件是 #include ,2.6 内核中需要包含的头文件则是

#include 。函数原型如下:

2.4 内核

int request_irq (

unsignedintirq,

void (

*handler)(

int,

void

*,

structpt_regs

*),

unsignedlongfrags,

constchar

*device,

void

*dev_id);

2.6 内核

request_irq(

unsignedintirq,irq_handler_thandler,

unsignedlongflags,

constchar

*name,

void

*dev);

参数说明:

在发生对应于第 1个参数

irq 的中断时,则调用第 2 个参数

handler 为要注册的中断服务函数(也就是把 handler() 中断服务函数注册到内核中 )。

第 3 个参数

flags 指定了

快速中断或中断共享等中断处理属性。在 2.6 教新的内核里(我的是 2.6.27 ~ 2.6.31 ),在 linux/interrupt.h 中定义操作这个参数的宏如下:

引用

/*

* These correspond to the IORESOURCE_IRQ_* defines in

* linux/ioport.h to select the interrupt line behaviour.  When

* requesting an interrupt without specifying a IRQF_TRIGGER, the

* setting should be assumed to be "as already configured", which

* may be as per machine or firmware initialisation.

#define IRQF_TRIGGER_NONE0x00000000

#define IRQF_TRIGGER_RISING0x00000001

#define IRQF_TRIGGER_FALLING0x00000002

#define IRQF_TRIGGER_HIGH0x00000004

指定中断触发类型:高电平有效。新增加的标志

#define IRQF_TRIGGER_LOW0x00000008

#define IRQF_TRIGGER_MASK(IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \

IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)

#define IRQF_TRIGGER_PROBE0x00000010

/*

* These flags used only by the kernel as part of the irq handling routines.

*registered first in an shared interrupt is considered for

*                performance reasons)

*/

#define IRQF_DISABLED           0x00000020

* IRQF_DISABLED - keep irqs disabled when calling the action handler

#define IRQF_SAMPLE_RANDOM      0x00000040

* IRQF_SAMPLE_RANDOM - irq is used to feed the random generator

#define IRQF_SHARED             0x00000080* IRQF_SHARED - allow sharing the irq among several devices

#define IRQF_PROBE_SHARED       0x00000100

* IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur

#define IRQF_TIMER              0x00000200

* IRQF_TIMER - Flag to mark this interrupt as timer interrupt

#define IRQF_PERCPU             0x00000400

* IRQF_PERCPU - Interrupt is per cpu

#define IRQF_NOBALANCING        0x00000800

* IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing

#define IRQF_IRQPOLL            0x00001000

* IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is

早期一点的 2.6 内核这里一般以 SA_ 前缀开头,如:

SA_INTERRUPT   表示禁止其他中断;(对应于 IRQF_DISABLED )

SA_SHIRQ             表示共享相同的中断号 (对应于 IRQF_SHARED )

SA_SAMPLE_RANDOM   此宏会影响到 RANDOM 的处理( 对应于 IRQF_SAMPLE_RANDOM )。

第 4 个参数

name,通常是

设备驱动程序的名称。改值用在 /proc/interrupt 系统 (虚拟) 文件上,或内核发生中断错误时使用。

第 5 个参数

dev_id 中断名称 可作为共享中断时的中断区别参数,也可以用来指定中断服务函数需要参考的数据地址。建议将

设备结构指针作为

dev_id参数

int request_irq(unsigned int irq, irq_handler_t handler,IRQF_SHARED, const char *devname, void *dev_id)

很多权威资料中都提到,中断共享注册时的注册函数中的dev_id参数是必不可少的,并且dev_id的值必须唯一。那么这里提供唯一的dev_id值的究竟是做什么用的?

根据我们前面中断模型的知识,可以看出发生中断时,内核并不判断究竟是共享中断线上的哪个设备产生了中断,它会循环执行所有该中断线上注册的中断处理函数(即irqaction->handler函数)。因此irqaction->handler函数有责任识别出是否是自己的硬件设备产生了中断,然后再执行该中断处理函数。通常是通过读取该硬件设备提供的中断flag标志位进行判断。那既然kernel循环执行该中断线上注册的所有irqaction->handler函数,把识别究竟是哪个硬件设备产生了中断这件事交给中断处理函数本身去做,那request_irq的dev_id参数究竟是做什么用的?

很多资料中都建议将设备结构指针作为dev_id参数。在中断到来时,迅速地根据硬件寄存器中的信息比照传入的dev_id参数判断是否是本设备的中断,若不是,应迅速返回。这样的说法没有问题,也是我们编程时都遵循的方法。但事实上并不能够说明为什么中断共享必须要设置dev_id。

下面解释一下dev_id参数为什么必须的,而且是必须唯一的。

当调用free_irq注销中断处理函数时(通常卸载驱动时其中断处理函数也会被注销掉),因为dev_id是唯一的,所以可以通过它来判断从共享中断线上的多个中断处理程序中删除指定的一个。如果没有这个参数,那么kernel不可能知道给定的中断线上到底要删除哪一个处理程序。

注销函数定义在Kernel/irq/manage.c中定义: void free_irq(unsigned int irq, void *dev_id)

返回值:

函数运行正常时返回 0 ,否则返回对应错误的负值。

示例代码片段:

引用

irqreturn_t xxx_interrupt (intirq,void*dev_id)

{

...

return (IRQ_HANDLED);

}

int xxx_open (struct inode *inode,structfile*filp)

{

if (!request_irq (XXX_IRQ,xxx_interruppt,IRQF_DISABLED,"xxx",NULL)){

/*正常注册*/

}

return (0);

}

============================================================================

内核中的中断处理模型

内核版本: Linux 2.6.19

Kernel中断处理模型结构图如下:

下面简单介绍一下:

1. Linux定义了名字为irq_desc的中断例程描述符表:(include/linux/irq.h)

struct irqdesc irq_desc[NR_IRQS];

NR_IRQS表示中断源的数目。

2. irq_desc[]是一个指向irq_desc结构的数组, irq_desc结构是各个设备中断服务例程的描述符。

struct irq_desc {

irq_flow_handler_t handle_irq;

struct irq_chip *chip;

void *handler_data;

void *chip_data;

struct irqaction *action;unsigned int status;

unsigned intdepth;unsigned int wake_depth;unsigned int irq_count;unsigned int irqs_unhandled;

spinlock_t lock;

#ifdef CONFIG_SMP

cpumask_t affinity;

unsigned int cpu;

#endif

#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)

cpumask_t pending_mask;

#endif

#ifdef CONFIG_PROC_FS

struct proc_dir_entry*dir;

#endif

const char *name;

} ____cacheline_aligned;

Irq_desc结构体中的成员action指向该中断号对应的irqaction结构体链表。Irqaction结构体定义如下:

// include/linux/interrupt.hstruct irqaction{

irq_handler_t handler; // 指向中断服务程序

unsigned long flags; // 中断标志

unsigned long mask; // 中断掩码

const char *name;// I/O设备名

void *dev_id;// 设备标识

struct irqaction*next;// 指向下一个描述符

int irq;// IRQ线

struct proc_dir_entry *dir; // 指向IRQn相关的/proc/irq/n目录的描述符

};

其中关键的handler成员指向了该设备的中断服务程序,由执行request_irq时建立。

3.在驱动程序初始化时,若使用到中断,通常调用函数request_irq()建立该驱动程序对应的irqaction结构体,并把它登记到irq_desc [irq_num]->action链表中。Iqr_num为驱动程序申请的中断号。

request_irq()函数的原型如下:

// kernel/irq/manage.cint request_irq(unsignedint irq,

irqreturn_t (*handler)(int,void*,struct pt_regs*),

unsignedlong irqflags,

const char *devname,

void *dev_id);

参数irq是设备中断求号,在向irq_desc []数组登记时,它做为数组的下标。把中断号为irq的irqaction结构体的首地址写入irq_desc [irq]->action。这样就把设备的中断请求号与该设备的中断服务例程irqaction联系在一起了。

这样当CPU接收到中断请求后,就可以根据中断号通过irq_desc []找到该设备的中断服务程序。流程如上图所示。

4. 关于共享中断

共享中断的不同设备的iqraction结构体都会添加进该中断号对应的irq_desc结构体的action成员所指向的irqaction链表内。当内核发生中断时,它会依次调用该链表内所有的handler函数。因此,若驱动程序需要使用共享中断机制,其中断处理函数必须有能力识别是否是自己的硬件产生了中断。通常是通过读取该硬件设备提供的中断flag标志位进行判断。

linux 中断服务程序,request_irq() linux注册中断服务相关推荐

  1. request_irq() | 注册中断服务【ZT】

    http://blog.csdn.net/wealoong/article/details/7566546 一.中断注册方法 在linux内核中用于申请中断的函数是request_irq(),函数原型 ...

  2. Linux 0.11 内核解析:中断相关(1)asm.s文件中断处理分析

    0 源代码 有两个版本的,一个是带中文注释,Intel格式的:一个是不带注释是AT&T格式的. Linux 0.11 中文注释版 Linux 0.11 源码,基于<Linux内核完全注释 ...

  3. :I/O中断处理过程包括哪几个阶段?中断服务程序流程分为哪几部分?

    完整的中断处理过程分为 1)中断响应的事前准备: 系统要想能够应对各种不同的中断信号,总的来看就是需要知道每种信号应该由哪个中断服务程序负责以及这些中断服务程序具体是如何工作的.系统只有事前对这两件事 ...

  4. 五、中断服务程序的流程

    1.中断服务程序的流程 保护现场.中断服务.恢复现场.中断返回 # 保护现场:程序断点的保护(中断隐指令完成),寄存器内容的保护(进栈指令). 保护程序的断点  包含了两部分内容 1).中断返回以后. ...

  5. c语言程序 中断函数示例,单片机_C语言函数_中断函数(中断服务程序)

    c语言中的中断函数注意事项 单片机_C语言函数_中断函数(中断服务程序) 在开始写中断函数之前,我们来一起回顾一下,单片机的中断系统. 中断的意思(学习过微机原理与接口技术的同学,没学过单片机,也应该 ...

  6. 中断服务程序(ISR)

    中断服务程序 关键词:软中断.中断向量.中断向量表.TSR内存驻留.DOS重入.中断请求.段地址.偏移量.寄存器.BIOS.DOS.setvect ( ).getvect ( ).keep ( ).d ...

  7. 嵌入式中的中断服务程序

    嵌入式中的中断服务程序 中断是嵌入式系统中重要的组成部分,但是在标准 C 中不包含中断.许多编译开发商在标准 C 上增加了对中断的支持,提供新的关键字用于标示中断服务程序(ISR),类似于__inte ...

  8. linux中断处理汇编入口,Linux中断处理体系结构分析(一)

    中断也是一种异常,之所以把它单独的列出来,是因为中断的处理与具体的开发板密切相关,除一些必须.共用的中断(比如系统时钟中断.片内外设UART中断)外,必须由驱动开发者提供处理函数.内核提炼出中断处理的 ...

  9. 中断触发流程三(中断控制器)

    这一篇主要说说中断控制器,及GPIO中断触发与中断号的识别,为什么GPIO引脚的触发最后调用特定的中断例程,这中间是怎么联系起来的.现在知道的是request_irq只是在特定的中断号 链表中注册了一 ...

最新文章

  1. gitblit mysql_Gitblit服务器搭建及IDEA整合Git使用
  2. C++:15---异常机制
  3. Android UI学习之---Button
  4. 地理国情监测云平台简介
  5. 数字滤波器设计——Matlab(理想低通滤波器、FIR滤波器)
  6. jmeter使用不同数据进行post请求测试:csv配置使用
  7. 摄像机成像原理(模型)与标定
  8. Vue.js实现文章评论和回复评论功能
  9. 439、Java框架93 -【SpringMVC - 拦截器】 2020.12.14
  10. java中高级面试_中高级面试常问:Java面向对象设计的六大原则
  11. 协会分享 | 如何推动EOS区块链技术在高校的落地
  12. 用java代码输出我爱你_这是一段Java程序员写给最爱的老婆的代码。
  13. RHCE认证考试心得(转)
  14. 【exe4j】如何利用exe4j把java桌面程序生成exe文件
  15. pwm控制直流电机转速流程图_直流电机的PWM速度控制程序
  16. tiktok设备注册+xg xk xl xa签名
  17. nyoj663弟弟的作业
  18. 这款TWS蓝牙耳机颜值与实用性到底怎么样?
  19. PHY6252国产低功耗蓝牙5.2 SoC芯片智能手环/智能家居方案替代NRF52810
  20. python遥感图像处理_基于Python的矿山遥感监测系统开发方法

热门文章

  1. mysql cast报错_mysql数据库cast
  2. IDirect3DDevice9::SetClipPlane
  3. MySQL数据库 --基础
  4. PMP备考指南之第一章:引论
  5. mysql 命令导入sql文件导出sql文件
  6. 谈谈一些有趣的CSS题目(十四)-- 纯 CSS 方式实现 CSS 动画的暂停与播放!
  7. CentOS 6.5高可用集群LVS+Keepalived
  8. Annotation实战【自定义AbstractProcessor】
  9. dedecms后台崩溃或者后台访问慢的解决方法
  10. (原)Mac下Apache添加限制IP线程模块:mod_limitipconn.so