Linux中断处理过程浅析
- 格式:doc
- 大小:149.50 KB
- 文档页数:9
完整的中断处理过程的教学探讨作者:黄涛来源:《城市建设理论研究》2012年第31期摘要:计算机系统对意外事件的处理是通过中断技术来实现。
对一具体中断事件的处理划分为中断响应、中断服务及中断返回三个过程,在专业教学中学生对此很容易理解,但对中断系统在操作系统中的组织、具体处理过程及过程间的衔接常常感到不解,本文以Linux系统为例作了较了详细的介绍。
关键词:中断中断向量中断描述符中图分类号:G424.21 文献标识码:A 文章编号:在i386中根据CPU和中断源间的时序关系,将中断分为同步中断和异步中断两大类。
同步中断称为异常(Exception),是指CPU执行指令时所产生的中断;异步中断称为中断(Interrupt),是指由I/O设备随机产生的中断。
异常和中断在操作系统中没有本质上的差异,二者间的差异主要在于中断向量的形成方式不同。
中断系统的软硬件组织:1、中断系统的硬件组织现代计算机中中断硬件系统是由I/O设备、中断控制器及CPU组成的三级层次结构。
逻辑结构如下所示:中断控制器的主要功能是将I/O设备的IRQ中断请求信号转换为CPU的中断请求信号;向CPU提供I/O设备的中断向量以找到中断服务程序。
在现代微机中一般采用8259A芯片。
2、Linux系统中断的软件组织(1)中断向量每一个异常和中断都有一个唯一的编号,称为中断向量,在Linux中使用0~255之间的无符号整数来表示。
在Linux中具体分配如下:0~31用于异常和不可屏蔽中断;32~47用于可屏蔽中断;48~255用于软中断。
(2)中断描述符中断描述符主要用来反映中断向量与中断服务程序间的对应关系。
中断描述符共占用8个字节,其格式如下:15~0位偏移量15~0位选择器0 0 0 字计数 P DPL 0 类型31~16位偏移量其中:字计数表示参数数量,5位;P是存在位;DPL是描述符特权级,2位;类型占用4位,共有任务门、调用门、中断门、陷阱门四种。
Linux中request_irq()中断申请与处理说明1、中断的理解中断你可以理解为就是⼀种电信号,是由硬件设备产⽣的然后发送给处理器,处理器接收到中断后,就会马上向操作系统反映此信号,之后就是系统的⼯作了。
这⾥有两个注意的地⽅,第⼀中断是随时都可以产⽣,意味着中断的处理程序随时都可以执⾏,所以得保证中断处理程序能够快速执⾏,才可能尽快的恢复中断代码执⾏,所以中断代码尽量简短。
第⼆每⼀个中断都有⾃⼰唯⼀的数字标记,这样操作系统才能对症下药2、注册中断中断处理程序中断处理程序是管理硬件的驱动程序的组成部分,每⼀设备都有相关的驱动程序,驱动程序可以通过request_irq()函数注册⼀个中断处理程序,并且激活给定的中断线,来处理指定的中断,原型如下:int request_irq(unsigned int irq,irq_handler_t handler,unsigned long flags, const char *devname, void *dev_id)第⼀个参数irq表⽰要分配的中断号,就我⽬前所接触的都是预先已经预定好的,还没试着通过探测或者动态来确定中断号第⼆个参数handler是⼀个指针,指向处理这个中断的实际中断处理程序,只要操作系统⼀接收到中断,该函数就被调⽤,这个函数稍后讨论第三个参数flags中断处理程序的标志,这个标志可以是⼀个也可以是多个,列举⼏个最重要的标志:IRQF_DISABLED: 该标志被设置后,意味内核在处理中断处理程序本⾝的时候,禁⽌了其他所有的中断。
如果不设置,中断处理程序可以与除本⾝之外的其他任何中断同时运⾏。
显⽽易见我们⼀般不去这么野蛮的设置这个标志IRQF_TIMER:为系统定时器的中断处理⽽准备的IRQF_SHARED:这个中断标志经常能遇见,这个标志意思就是多个中断处理程序之间可以共享中断线,概括起来就是没有这个标志就只能独⾃⼀个⼈占⽤,标志了,就是很多⼈可以占⽤这个中断号来第四个才参数就是⾃定义与中断设备相关的⽂本了第五个参数dev,看到第三个参数中IRQF_SHARED时候,你会不会有这样的疑问,假如现在我要释放当前共享的指定这个中断程序时候,我如何释放?会不会把其他占⽤也会删除掉,这就是第五个参数的意义,如果中断线是共享的,那么就必须传递能够代表当前设备的唯⼀信息request_irq()成功返回0,如果返回⾮0,就表⽰有错误发⽣,这个时候你可以考虑当前中断是否被占⽤了,所以可以加上IRQF_SHARED标志3、中断处理程序这⾥延续上⾯的handler指针,原型如下:Static irqreturn_t intr_handler(int irq, void *dev)这⾥唠叨⼀下,不知道⼤家⾯试时候有没有遇到像这样的题⽬__interrupt double compute_area (double radius){double area = PI * radius * radius;printf(" Area = %f", area);return area;},指出上⾯中断函数出现的错误,不知道的就认真看下⾯的 O(∩_∩)O第⼀个参数irq就是这个处理程序要响应的中断号,这个我认为现在没有多⼤意义了,因为上⾯有讲述到第五个参数的意义第⼆个参数dev是⼀个通⽤的指针,同样的,还是将上⾯讲述到的第五个参数拿过来理解。
Linux中断处理流程1. 中断处理流程 当中断发⽣时,Linux系统会跳转到asm_do_IRQ()函数(所有中断程序的总⼊⼝函数),并且把中断号irq传进来。
根据中断号,找到中断号对应的irq_desc结构(irq_desc结构为内核中中断的描述结构,内核中有⼀个irq_desc结构的数组irq_desc_ptrs[NR_IRQS]),然后调⽤irq_desc中的handle_irq函数,即中断⼊⼝函数。
我们编写中断的驱动,即填充并注册irq_desc结构。
2. 中断处理数据结构:irq_desc Linux内核将所有的中断统⼀编号,使⽤⼀个irq_desc[NR_IRQS]的结构体数组来描述这些中断:每个数组项对应着⼀个中断源(也可能是⼀组中断源),记录中断⼊⼝函数、中断标记,并提供了中断的底层硬件访问函数(中断清除、屏蔽、使能)。
另外通过这个结构体数组项中的action,能够找到⽤户注册的中断处理函数。
struct irq_desc {unsigned int irq;irq_flow_handler_t handle_irq;struct irq_chip *chip;struct msi_desc *msi_desc;void *handler_data;void *chip_data;struct irqaction *action; /* IRQ action list */unsigned int status; /* IRQ status */unsigned int depth; /* nested irq disables */unsigned int wake_depth; /* nested wake enables */unsigned int irq_count; /* For detecting broken IRQs */unsigned long last_unhandled; /* Aging timer for unhandled count */unsigned int irqs_unhandled;spinlock_t lock;const char *name;} ____cacheline_internodealigned_in_smp;(1)handle_irq:中断的⼊⼝函数(2)chip:包含这个中断的清除、屏蔽、使能等底层函数struct irq_chip {const char *name;unsigned int (*startup)(unsigned int irq);void (*shutdown)(unsigned int irq);void (*enable)(unsigned int irq);void (*disable)(unsigned int irq);void (*ack)(unsigned int irq);void (*mask)(unsigned int irq);void (*mask_ack)(unsigned int irq);void (*unmask)(unsigned int irq);void (*eoi)(unsigned int irq);void (*end)(unsigned int irq);void (*set_affinity)(unsigned int irq,const struct cpumask *dest);int (*retrigger)(unsigned int irq);int (*set_type)(unsigned int irq, unsigned int flow_type);int (*set_wake)(unsigned int irq, unsigned int on);/* Currently used only by UML, might disappear one day.*/#ifdef CONFIG_IRQ_RELEASE_METHODvoid (*release)(unsigned int irq, void *dev_id);#endif/** For compatibility, ->typename is copied into ->name.* Will disappear.*/const char *typename;};(3)action:记录⽤户注册的中断处理函数、中断标志等内容struct irqaction {irq_handler_t handler;unsigned long flags;cpumask_t mask;const char *name;void *dev_id;struct irqaction *next;int irq;struct proc_dir_entry *dir;};3. 中断处理流程总结(1)发⽣中断后,CPU执⾏异常向量vector_irq的代码;(2)在vector_irq⾥⾯,最终会调⽤中断处理C程序总⼊⼝函数asm_do_IRQ();(3)asm_do_IRQ()根据中断号调⽤irq_des[NR_IRQS]数组中的对应数组项中的handle_irq();(4)handle_irq()会使⽤chip的成员函数来设置硬件,例如清除中断,禁⽌中断,重新开启中断等;(5)handle_irq逐个调⽤⽤户在action链表中注册的处理函数。
x86 linux内核中断处理流程下载温馨提示:该文档是我店铺精心编制而成,希望大家下载以后,能够帮助大家解决实际的问题。
文档下载后可定制随意修改,请根据实际需要进行相应的调整和使用,谢谢!并且,本店铺为大家提供各种各样类型的实用资料,如教育随笔、日记赏析、句子摘抄、古诗大全、经典美文、话题作文、工作总结、词语解析、文案摘录、其他资料等等,如想了解不同资料格式和写法,敬请关注!Download tips: This document is carefully compiled by theeditor.I hope that after you download them,they can help yousolve practical problems. The document can be customized andmodified after downloading,please adjust and use it according toactual needs, thank you!In addition, our shop provides you with various types ofpractical materials,such as educational essays, diaryappreciation,sentence excerpts,ancient poems,classic articles,topic composition,work summary,word parsing,copy excerpts,other materials and so on,want to know different data formats andwriting methods,please pay attention!深入解析x86 Linux内核中断处理机制在计算机系统中,中断扮演着至关重要的角色,它使得硬件事件能够及时通知操作系统进行相应的处理。
论述linux操作系统处理中断的过程。
Linux操作系统是一种开源的、自由的、类Unix操作系统,它的内核是由Linus Torvalds和全球志愿者团队开发的。
Linux内核的一个重要功能是处理中断,它可以使操作系统在执行某个任务时,直接响应外部的事件,如键盘输入、网络数据传输等。
本文将详细介绍Linux操作系统处理中断的过程。
1. 中断的概念中断是指计算机在执行某个任务时,被外部事件所打断,暂停当前任务的执行,转而去处理其他任务的一种机制。
中断可以分为硬件中断和软件中断两种。
硬件中断是指计算机硬件设备发出的中断信号,如键盘、鼠标、网络接口卡等。
当硬件设备发出中断信号时,CPU会暂停当前任务的执行,跳转到中断服务程序中去执行处理,处理完中断后再返回原来的任务。
软件中断是指操作系统内核发出的中断信号,可以通过系统调用的方式触发,如定时器中断、系统调用等。
软件中断和硬件中断的处理方式是相同的。
2. 中断的分类根据中断的优先级,中断可以分为以下几类:① 外部中断:由硬件设备发出,如键盘输入、鼠标移动、网络数据传输等,优先级最高。
② 内部中断:由软件程序触发,如定时器中断、系统调用等,优先级次之。
③ 异常中断:由于程序执行错误或硬件故障等原因而发生的中断,优先级最低。
3. 中断的处理过程在Linux操作系统中,中断处理的过程可以分为以下几个步骤:① 中断请求:当硬件设备发出中断请求信号时,会将中断请求信号发送给中断控制器,中断控制器会将中断请求信号发送给CPU。
② 中断响应:CPU接收到中断请求信号后,会暂停当前任务的执行,跳转到中断服务程序中去执行处理。
在跳转之前,CPU会将当前任务的上下文保存到内存中,以便后续恢复任务的执行。
③ 中断处理:中断服务程序会根据中断类型进行相应的处理,如读取键盘输入、发送网络数据等。
在处理过程中,中断服务程序可以访问进程内存空间、内核内存空间等,并可以与其他设备进行交互。
linux中断处理流程Linux中断处理流程Linux中断处理是操作系统中的一个重要组成部分,用于响应硬件设备的事件。
在Linux中,中断可以是外部中断,如硬件设备发送的中断信号,也可以是内部中断,如软件产生的异常或系统调用。
中断处理的目的是及时响应硬件设备的事件,并采取相应的措施来处理这些事件。
一、中断的触发中断是由硬件设备发送的一个信号,用于通知操作系统某个事件的发生。
这个信号可以是一个电平的变化,一个特定的数据包,或者一个指定的硬件寄存器的变化。
当硬件设备检测到某个事件发生时,它会向处理器发送一个中断信号,处理器会立即停止当前正在执行的任务,保存当前的上下文,并跳转到中断处理程序的入口点。
二、中断处理程序的执行中断处理程序是一个特殊的函数,负责处理中断事件。
当中断发生时,处理器会跳转到中断处理程序的入口点,并执行相应的代码。
中断处理程序的执行过程可以分为以下几个步骤:1. 保存上下文:在执行中断处理程序之前,处理器需要保存当前任务的上下文,包括程序计数器、寄存器和堆栈指针等。
这样可以确保在中断处理程序执行完成后,能够正确地返回到原来的任务。
2. 中断处理程序的执行:一旦保存了上下文,处理器就会执行中断处理程序的代码。
中断处理程序根据中断的类型,执行相应的操作。
例如,对于外部中断,中断处理程序可能需要读取硬件设备的状态,处理数据包或执行特定的操作。
对于内部中断,中断处理程序可能需要处理异常或系统调用。
3. 中断处理程序的结束:当中断处理程序执行完成后,处理器会恢复之前保存的上下文,并将控制权返回给原来的任务。
这样原来的任务就可以继续执行,而不会受到中断的影响。
三、中断处理的优先级在Linux中,中断处理有不同的优先级。
这是为了确保对于紧急事件的及时处理。
中断的优先级由硬件设备决定,通常是通过一个优先级编码器来实现的。
当多个中断同时发生时,处理器会按照优先级的顺序来处理中断。
高优先级的中断会立即被处理,而低优先级的中断则会被推迟到稍后处理。
linux系统中断详解最近为了解决风控问题,⼀直在研究linux的系统内核,经过⼀段时间的学习,先整理出⼀份关于linux中断的⼩记。
1.什么是中断?计算机cpu在执⾏task时,不可能每次都将任务执⾏完毕,会因为各种不同的场景⽽暂停执⾏,所谓中断就是这个暂停执⾏的过程。
2.中断算是⼀种错误吗?严格来说,中断当然算是运⾏错误的⼀种,但是,由于其不可避免,程序开发者⾃然可以将其视为⼀种机制,加以运⽤,反⽽更容易帮助我们完成现实功能的实现。
3.中断的分类从产⽣原因上看,中断可以分为软件中断和硬件中断,⽽从类别划分上看,也可以氛围有出错码中断和⽆出错码中断。
⼆者并不排斥,⽐如说,中断分类存在int0~int255中,其中int0 ~ int31 表⽰软件中断,int32 ~ int255: 可由⽤户⾃⼰设置。
其中int32 ~ int47 对应8259A的IRQ0 ~ IRQ15中断。
需要注意的是,int128 为系统调⽤中断(system_call)。
如果⼤家有看过内核源码或者其他汇编代码,会发现汇编语⾔在调⽤c函数时,就是使⽤system_call,由此可见,调⽤其他函数,也是⼀种中断。
这⾥不⽌局限于linux系统,其中中断逻辑囊括所有计算机逻辑执⾏逻辑,其最基础的实现逻辑就是计算机0/1与或逻辑,属于机器语⾔中最低级也是最⾼效的展现形式。
4.中断时堆栈变化情况堆栈相关知识此处不做介绍,不了解的同学可以⾃⾏查找⼀下相关资料。
上图可以⾮常清楚的展⽰中断发⽣时堆栈的变化情况。
即中断发⽣前,需要将图中的信息按照先后顺序,压⼊中断处理程序的堆栈中。
下⾯进⾏具体的分析:SS(stack segment): 堆栈段ESP(extended stack pointer): 堆栈指针EFLAGS : 状态标志寄存器CS(code segment): 代码段EIP(extended instruction pointer) : 中断后要执⾏的下⼀条指令的地址1)有/⽆出错码:我们只需知道,对于某些中断,⽐如:int0(⽆错误码)是不需要保存出错码的,⽽像int8等中断是需要保存出错码的。
中断处理流程linux中断处理浅析最近在研究异步消息处理, 突然想起linux内核的中断处理, ⾥⾯由始⾄终都贯穿着"重要的事马上做, 不重要的事推后做"的异步处理思想. 于是整理⼀下~第⼀阶段--获取中断号每个CPU都有响应中断的能⼒, 每个CPU响应中断时都⾛相同的流程. 这个流程就是内核提供的中断服务程序.在进⼊中断服务程序时, CPU已经⾃动禁⽌了本CPU上的中断响应, 因为CPU不能假定中断服务程序是可重⼊的.中断处理程序的第⼀步要做两件事情:1. 将中断号压⼊栈中; (不同中断号的中断对应不同的中断服务程序⼊⼝)2. 将当前寄存器信息压⼊栈中; (以便中断退出时恢复)显然, 这两步都是不可重⼊的(如果在保存寄存器值时被中断了, 那么另外的操作很可能就把寄存器给改写了, 现场将⽆法恢复), 所以前⾯说到的CPU进⼊中断服务程序时要⾃动禁⽌中断.栈上的信息被作为函数参数, 调⽤do_IRQ函数.第⼆阶段--中断串⾏化进⼊do_IRQ函数, 第⼀步进⾏中断的串⾏化处理, 将多个CPU同时产⽣的某⼀中断进⾏串⾏化.其⽅法是如果当前中断处于"执⾏"状态(表明另⼀个CPU正在处理相同的中断), 则重新设置它的"触发"标记, 然后⽴即返回. 正在处理同⼀中断的那个CPU完成⼀次处理后, 会再次检查"触发"标记, 如果设置, 则再次触发处理过程.于是, 中断的处理是⼀个循环过程, 每次循环调⽤handle_IRQ_event来处理中断.第三阶段--关中断条件下的中断处理进⼊handle_IRQ_event函数, 调⽤对应的内核或内核模块通过request_irq函数注册的中断处理函数.注册的中断处理函数有个中断开关属性, ⼀般情况下, 中断处理函数总是在关中断的情况下进⾏的. ⽽调⽤request_irq注册中断处理函数时也可以设置该中断处理函数在开中断的情况下进⾏,这种情况⽐较少见, 因为这要求中断处理代码必须是可重⼊的. (另外, 这⾥如果开中断, 正在处理的这个中断⼀般也是会被阻塞的. 因为正在处理某个中断的时候, 硬件中断控制器上的这个中断并未被ack, 硬件不会发起下⼀次相同的中断.)中断处理函数的过程可能会很长, 如果整个过程都在关中断的情况下进⾏, 那么后续的中断将被阻塞很长的时间.于是, 有了soft_irq. 把不可重⼊的⼀部分在中断处理程序中(关中断)去完成, 然后调⽤raise_softirq 设置⼀个软中断, 中断处理程序结束. 后⾯的⼯作将放在soft_irq⾥⾯去做.第四阶段--开中断条件下的软中断上⼀阶段循环调⽤完当前所有被触发的中断处理函数后, do_softirq函数被调⽤, 开始处理软件中断.在软中断机制中, 为每个CPU维护了⼀个若⼲位的掩码集, 每位掩码代表⼀个中断号. 在上⼀阶段的中断处理函数中, 调⽤raise_softirq设置了对应的软中断, 到了这⾥, 软中断对应的处理函数就会被调⽤(处理函数由open_softirq函数来注册).可以看出, 软中断与中断的模型很类似, 每个CPU有⼀组中断号, 中断有其对应的优先级, 每个CPU处理属于⾃⼰的中断. 最⼤的不同是开中断与关中断.于是, ⼀个中断处理过程被分成了两部分, 第⼀部分在中断处理函数⾥⾯关中断的进⾏, 第⼆部分在软中断处理函数⾥⾯开中断的进⾏.由于这⼀步是在开中断条件下进⾏的,这⾥还可能发⽣新的中断(中断嵌套),然后新中断对应的中断处理⼜将开始⼀个新的第⼀阶段~第三阶段。
linux内核中断处理的irq_thread机制-回复Linux内核中断处理的irq_thread机制是一种处理中断请求的机制,旨在提高中断处理的效率和可扩展性。
在本文中,我们将详细介绍irq_thread 的原理和实现细节,并分析其对系统性能的影响。
一、引言随着计算机系统的发展,硬件设备的种类和数量不断增加,从而引发了对中断处理的需求。
在传统中断处理模式下,Linux内核需要通过一个叫做中断处理程序(interrupt handler)的功能模块来处理硬件设备发出的中断请求。
然而,这种模式在多核系统和高速设备的环境下往往存在性能瓶颈和可扩展性问题。
为了解决这些问题,Linux内核引入了irq_thread机制。
二、irq_thread机制的原理irq_thread机制的核心思想是将中断处理程序从内核上下文中移出,转而在用户态创建一个专门的线程来处理中断请求。
这个线程被称为irq_thread。
irq_thread在内核注册的中断向量表中占据一个特殊的槽位,当对应的硬件设备发生中断时,硬件会触发相应的中断请求,并将中断处理程序的控制权交给irq_thread。
在irq_thread的实现中,内核通过分配一个独立的线程栈和一组寄存器保存irq_thread的上下文。
同时,irq_thread中还有一个运行队列,用于保存需要处理的中断任务。
当一个中断请求到达时,irq_thread会从硬件设备读取中断状况,并将相应的中断任务放入运行队列。
三、irq_thread机制的实现细节1. 中断控制器:irq_thread机制需要硬件支持,其中关键的组件是中断控制器(interrupt controller)。
中断控制器是一种硬件设备,用于管理和分发中断请求。
在Linux内核中,主流的中断控制器有APIC(Advanced Programmable Interrupt Controller)和IOAPIC(Input/Output Advanced Programmable Interrupt Controller)等。
linux中断响应和处理过程:首先中断属于异常的一种。
异常,就是可以打断CPU正常运行流程的一些事情,比如说外部中断,未定义的指定,试图修改只读数据,执行SWI指定(software interrupt instructin,软件中断指令,比如说上层调用sys_read,sys_write就会产生swi)等。
内核启动时在start_kernel函数(init/main.c)中调用trap_init , init_IRQ两个函数来设置异常的处理函数。
trap_init函数(arch/arm/kernel/traps.c)void_init trap_init(void){......memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start); memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start); .......}上面两条定义的是异常向量的存放地方,即:__stubs_start~~~~~ __stubs_end之间就是异常向量.接下来我们看异常向量之间的定义:(arch/arm/kernel/entry-armv.s).equ stubs_offset, __vectors_start + 0x200 - __stubs_start.globl __vectors_start__vectors_start:ARM( swi SYS_ERROR0 ) //复位时.CPU交执行这条指令THUMB( svc #0 )THUMB( nop )W(b) vector_und + stubs_offset //未定义异常时,CPU将执行这条跳转指令W(ldr) pc, .LCvswi + stubs_offset //swi异常W(b) vector_pabt + stubs_offset //指令预取止W(b) vector_dabt + stubs_offset //数据访问中止W(b) vector_addrexcptn + stubs_offset //没有用到W(b) vector_irq + stubs_offset //irq中断W(b) vector_fiq + stubs_offset //fig中断(快速中断).globl __vectors_end__vectors_end:各种异常的处理函数可以分为五类,分别分布在下面不同的文件中:1、arch/arm/kernel/traps.c中处理未定义指令异常,总入口函数为do_undefinstr2、arch/arm/mm/fault.c与内存访问相关的异常,总入口函数为do_DataAbort, do_PretftchAbort3. arch/arm/mm/irq.c中断处理函数在这个文件中定义,总入口函数为asm_do_IRQ4. arch/arm/kernel/call.sswi异常处理比如说:sys_read, sys_open等.5. 没有使用的异常除了IRQ中断外(FIG中断linux一般不使用),所有的异常内核都定义了细致而完备的处理函数. 所以我们这里关心的也只是上面红色部分,即:IRQ中断.Init_IRQ函数(arch/arm/kernel/irq.c),被用来初使化中断的处理框架,设置各种中断的默认处理函数.Linux内核将所有中断统一编号,使用irq_desc结构来描述中断:每个数组项对应一个中断(也可能是一组中断,它们使用共同的中断号),里面记录了中断的名称,中断状态,中断标记,并提供硬件访问函数(清除,屏蔽,使能中断),提供了这个中断的处理函数的入口,通过它可以调用用户注册的中断处理函数include/linux/irq.h{.........irq_flow_handler_t handle_irq; //当前的中断处理函数入口struct irq_chip *chip; //底层的硬件访问..........struct irqaction *action; //用户提供的中断处理函数链表unsigned int status; //IRQ状态...........const char *name; //中断名称} ____cacheline_internodealigned_in_smp;Handle_irq是这个或者这组中断的处理函数入口.当中断发生时总中断入口函数asm_do_IRQ将根据中断号调用相应irq_desc数组中的handle_irq函数,handle_irq使用chip结构中的函数来清除,屏蔽,使用中断,还会一一调用用户在action链表中注册的中断处理函数.Struct irq_chip{const char *name; //启动中断,如果不设置,缺省为"enable"unsigned int (*startup)(unsigned int irq); //启动中断,如果不设置,缺省为"enable" void (*shutdown)(unsigned int irq); //关闭中断,如果不设置,缺省为"disable"void (*enable)(unsigned int irq); //使能中断,如果不设置,缺省为unmaskvoid (*disable)(unsigned int irq); //禁止中断如果不设置,缺省为"mask"void (*ack)(unsigned int irq); //响应中断,通常是清除当前中断使得可以接收下一个中断void (*mask)(unsigned int irq); //屏蔽中断源void (*mask_ack)(unsigned int irq); //屏蔽和响应中断void (*unmask)(unsigned int irq); //开启中断源..........}struct irqaction *action; 结构类型在include/linux/interrupt..h中定义.用户注册的每一个中断处理函数都用一个irqaction结构表示,一个中断(比如共享中断)可以有多个处理函数,它们的irqacion结构链接成一个链表,以action为表头.struct irqaction {irq_handler_t handler; //用户注册的中断处理函数unsigned long flags;//中断标志,比如是否为共享中断,电平触发还是边沿触发const char *name; //用户注册的中断名字void *dev_id; //用户供给的handle参数,还可以区分共享中断struct irqaction *next;int irq; //中断号struct proc_dir_entry *dir;irq_handler_t thread_fn;struct task_struct *thread;unsigned long thread_flags;};Irq_desc结构数组中:"irq_flow_handler_thandle_irq" , "struct irq_chip *chip " , "struct ,ir qaction *action"这三种数据结构构成了中断处理体系结构.很明显,中断需要用户处理的只有最后一步,就是用户的action中断处理函数.所以我们需要告诉内核我们相应的中断处理函数在哪里,中断注册:reguest_irq, 相对应的中断卸载: free_irq.int request_irq(unsigned int irq, //中申请中断的中断号,可以根据不用的引脚到irqs.h里面查找irqreturn_t (*handler)(int, void *, struct pt_regs *),//用户写的中断处理函数unsigned long irqflags,//中断触发方式(高电平触发,低电平触发,上升沿,下降沿等)const char *devname,//中断名字(自己取名)void *dev_id); //dev_id(共享中断时,用于识别倒里是哪个硬件产生的中断)//同一中断的不同处理函数必须用dev_id来区分,//共享中断之间既可使用同一中断处理函数,也可使用不同中断处理函数,都需要dev_id区分.中断注册做了三件事:1.提供用户action中断处理函数链接2.中断触发方式是什么3.中断使能Void free_irq(unsigned int irq, //中断号与注册时对应void *dev_id) //共享中断时用于区分不同硬件与注册时对应中断卸载和注册相反:1.根据中断号irq,dev_id从action链表中找到表项,将它删除2.如果它是唯一表项,还要调用IRQ_DESC[IRQ].CHIP->SHUTDOWN或DESC[IRQ].CHIP->DISABLE来关闭中断.所以很显然,用户要自己写一个中断程序,只需要实现三步,1.向内核申请注册中断2.实现用户中断处理函数3.在不需要该中断的时候卸载中断附上一个例子:按键的中断程序驱动程序:#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <asm/irq.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#include <asm/arch/regs-gpio.h>#include <asm/hardware.h>#define DEVICE_NAME "buttons" /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称*/#define BUTTON_MAJOR 232 /* 主设备号*/struct button_irq_desc {unsigned long flags;char *name;};/* 用来指定按键所用的外部中断引脚及中断触发方式, 名字*/static struct button_irq_desc button_irqs [] = {{IRQ_EINT19, IRQF_TRIGGER_FALLING, "KEY1"}, /* K1 */{IRQ_EINT11, IRQF_TRIGGER_FALLING, "KEY2"}, /* K2 */{IRQ_EINT2, IRQF_TRIGGER_FALLING, "KEY3"}, /* K3 */{IRQ_EINT0, IRQF_TRIGGER_FALLING, "KEY4"}, /* K4 */};/* 按键被按下的次数(准确地说,是发生中断的次数) */static volatile int press_cnt [] = {0, 0, 0, 0};/* 等待队列:* 当没有按键被按下时,如果有进程调用s3c24xx_buttons_read函数,* 它将休眠*/static DECLARE_WAIT_QUEUE_HEAD(button_waitq);/* 中断事件标志, 中断服务程序将它置1,s3c24xx_buttons_read将它清0 */ static volatile int ev_press = 0;static irqreturn_t buttons_interrupt(int irq, void *dev_id){volatile int *press_cnt = (volatile int *)dev_id;*press_cnt = *press_cnt + 1; /* 按键计数加1 */ev_press = 1; /* 表示中断发生了*/wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程*/return IRQ_RETVAL(IRQ_HANDLED);}/* 应用程序对设备文件/dev/buttons执行open(...)时,* 就会调用s3c24xx_buttons_open函数*/static int s3c24xx_buttons_open(struct inode *inode, struct file *file) {int err;for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {// 注册中断处理函数err = request_irq(button_irqs[i].irq, buttons_interrupt, button_irqs[i] .flags,button_irqs[i].name, (void *)&press_cnt[i]);if (err)break;}if (err) {// 释放已经注册的中断i--;for (; i >= 0; i--)free_irq(button_irqs[i].irq, (void *)&press_cnt[i]);return -EBUSY;}return 0;}/* 应用程序对设备文件/dev/buttons执行close(...)时,* 就会调用s3c24xx_buttons_close函数*/static int s3c24xx_buttons_close(struct inode *inode, struct file *file){int i;for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {// 释放已经注册的中断free_irq(button_irqs[i].irq, (void *)&press_cnt[i]);}return 0;}/* 应用程序对设备文件/dev/buttons执行read(...)时,* 就会调用s3c24xx_buttons_read函数*/static int s3c24xx_buttons_read(struct file *filp, char __user *buff,size_t count, loff_t *offp){unsigned long err;/* 如果ev_press等于0,休眠*/wait_event_interruptible(button_waitq, ev_press);/* 执行到这里时,ev_press等于1,将它清0 */ev_press = 0;/* 将按键状态复制给用户,并清0 */err = copy_to_user(buff, (const void *)press_cnt, min(sizeof(press_cnt), co unt));memset((void *)press_cnt, 0, sizeof(press_cnt));return err ? -EFAULT : 0;}/* 这个结构是字符设备驱动程序的核心* 当应用程序操作设备文件时所调用的open、read、write等函数,* 最终会调用这个结构中的对应函数*/static struct file_operations s3c24xx_buttons_fops = {.owner = THIS_MODULE, /* 这是一个宏,指向编译模块时自动创建的__this_module变量*/.open = s3c24xx_buttons_open,.release = s3c24xx_buttons_close,.read = s3c24xx_buttons_read,};/** 执行“insmod s3c24xx_buttons.ko”命令时就会调用这个函数*/static int __init s3c24xx_buttons_init(void){int ret;/* 注册字符设备驱动程序* 参数为主设备号、设备名字、file_operations结构;* 这样,主设备号就和具体的file_operations结构联系起来了,* 操作主设备为BUTTON_MAJOR的设备文件时,就会调用s3c24xx_buttons_fops中的相关成员函数* BUTTON_MAJOR可以设为0,表示由内核自动分配主设备号*/ret = register_chrdev(BUTTON_MAJOR, DEVICE_NAME, &s3c24xx_buttons_fops);if (ret < 0) {printk(DEVICE_NAME " can't register major number\n");return ret;}printk(DEVICE_NAME " initialized\n");return 0;}/** 执行”rmmod s3c24xx_buttons.ko”命令时就会调用这个函数*/static void __exit s3c24xx_buttons_exit(void){/* 卸载驱动程序*/unregister_chrdev(BUTTON_MAJOR, DEVICE_NAME);}/* 这两行指定驱动程序的初始化函数和卸载函数*/module_init(s3c24xx_buttons_init);module_exit(s3c24xx_buttons_exit);/* 描述驱动程序的一些信息,不是必须的*/MODULE_AUTHOR(""); // 驱动程序的作者MODULE_DESCRIPTION("S3C2410/S3C2440 BUTTON Driver"); // 一些描述信息MODULE_LICENSE("GPL"); // 遵循的协议///。