Linux中断处理过程浅析

合集下载

完整的中断处理过程的教学探讨

完整的中断处理过程的教学探讨

完整的中断处理过程的教学探讨作者:黄涛来源:《城市建设理论研究》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()中断申请与处理说明

Linux中request_irq()中断申请与处理说明

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中断处理流程

Linux中断处理流程

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内核中断处理流程

x86 linux内核中断处理流程

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操作系统处理中断的过程。

论述linux操作系统处理中断的过程。

Linux操作系统是一种开源的、自由的、类Unix操作系统,它的内核是由Linus Torvalds和全球志愿者团队开发的。

Linux内核的一个重要功能是处理中断,它可以使操作系统在执行某个任务时,直接响应外部的事件,如键盘输入、网络数据传输等。

本文将详细介绍Linux操作系统处理中断的过程。

1. 中断的概念中断是指计算机在执行某个任务时,被外部事件所打断,暂停当前任务的执行,转而去处理其他任务的一种机制。

中断可以分为硬件中断和软件中断两种。

硬件中断是指计算机硬件设备发出的中断信号,如键盘、鼠标、网络接口卡等。

当硬件设备发出中断信号时,CPU会暂停当前任务的执行,跳转到中断服务程序中去执行处理,处理完中断后再返回原来的任务。

软件中断是指操作系统内核发出的中断信号,可以通过系统调用的方式触发,如定时器中断、系统调用等。

软件中断和硬件中断的处理方式是相同的。

2. 中断的分类根据中断的优先级,中断可以分为以下几类:① 外部中断:由硬件设备发出,如键盘输入、鼠标移动、网络数据传输等,优先级最高。

② 内部中断:由软件程序触发,如定时器中断、系统调用等,优先级次之。

③ 异常中断:由于程序执行错误或硬件故障等原因而发生的中断,优先级最低。

3. 中断的处理过程在Linux操作系统中,中断处理的过程可以分为以下几个步骤:① 中断请求:当硬件设备发出中断请求信号时,会将中断请求信号发送给中断控制器,中断控制器会将中断请求信号发送给CPU。

② 中断响应:CPU接收到中断请求信号后,会暂停当前任务的执行,跳转到中断服务程序中去执行处理。

在跳转之前,CPU会将当前任务的上下文保存到内存中,以便后续恢复任务的执行。

③ 中断处理:中断服务程序会根据中断类型进行相应的处理,如读取键盘输入、发送网络数据等。

在处理过程中,中断服务程序可以访问进程内存空间、内核内存空间等,并可以与其他设备进行交互。

10-5 Linux操作系统 - 中断、异常及系统调用

10-5 Linux操作系统 - 中断、异常及系统调用

10.5.4 中断上半部分的处理 一、 中断控制器 •每个硬件设备控制器都能通过中断请求线 发出中断请求(简称IRQ) •所有设备的中断请求线又连到中断控制器 的输入端。 •在x86单CPU的机器上采用两个8259A芯片作 为中断控制器,一主一从。
•当8259A有中断信号输入同时中断信号不被 屏蔽时,主8259A向CPU发出 INT信号,请求 中断。这时如果CPU是处于允许中断状况, CPU就会发信号给8259A进入中断响应周期。 •在对8259A芯片的初始化过程中,第n号中 断在IDT表中的向量号为 n+32
•IDT中向量号的使用情况如下: 0-31 异常与非屏蔽中断使用。 32-47 可屏蔽中断使用32至47 128(0x80)实现系统调用。 其余 未使用 •保存现场 发生异常时在核心栈的程序计数器eip的 值取决于具体情况。一般情况下eip保存的 下一条指令的地址,但对于页面异常,保存 的产生异常的这条指令的地址而不是下一条 指令的地址
中断向量表IDT •IDT是中断/异常处理在内核的入口。IDT表 项还记录了一些其它信息用以安全检查。 •IDT在系统初始化时创建。 •每个中断/异常都有一个向量号,该号的值 在0-255之间,该值是中断/异常在IDT中的 索引。 •每个中断/异常均有其相应的处理函数,中 断/异常在使用前必须在IDT中注册信息以保 证发生中断/异常时能找到相应的处理函数。
struct hw_interrupt_type { const char * typename; 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 (*end)(unsigned int irq); void (*set_affinity)(unsigned int irq, unsigned long mask); };

linux中断处理流程

linux中断处理流程

linux中断处理流程Linux中断处理流程Linux中断处理是操作系统中的一个重要组成部分,用于响应硬件设备的事件。

在Linux中,中断可以是外部中断,如硬件设备发送的中断信号,也可以是内部中断,如软件产生的异常或系统调用。

中断处理的目的是及时响应硬件设备的事件,并采取相应的措施来处理这些事件。

一、中断的触发中断是由硬件设备发送的一个信号,用于通知操作系统某个事件的发生。

这个信号可以是一个电平的变化,一个特定的数据包,或者一个指定的硬件寄存器的变化。

当硬件设备检测到某个事件发生时,它会向处理器发送一个中断信号,处理器会立即停止当前正在执行的任务,保存当前的上下文,并跳转到中断处理程序的入口点。

二、中断处理程序的执行中断处理程序是一个特殊的函数,负责处理中断事件。

当中断发生时,处理器会跳转到中断处理程序的入口点,并执行相应的代码。

中断处理程序的执行过程可以分为以下几个步骤:1. 保存上下文:在执行中断处理程序之前,处理器需要保存当前任务的上下文,包括程序计数器、寄存器和堆栈指针等。

这样可以确保在中断处理程序执行完成后,能够正确地返回到原来的任务。

2. 中断处理程序的执行:一旦保存了上下文,处理器就会执行中断处理程序的代码。

中断处理程序根据中断的类型,执行相应的操作。

例如,对于外部中断,中断处理程序可能需要读取硬件设备的状态,处理数据包或执行特定的操作。

对于内部中断,中断处理程序可能需要处理异常或系统调用。

3. 中断处理程序的结束:当中断处理程序执行完成后,处理器会恢复之前保存的上下文,并将控制权返回给原来的任务。

这样原来的任务就可以继续执行,而不会受到中断的影响。

三、中断处理的优先级在Linux中,中断处理有不同的优先级。

这是为了确保对于紧急事件的及时处理。

中断的优先级由硬件设备决定,通常是通过一个优先级编码器来实现的。

当多个中断同时发生时,处理器会按照优先级的顺序来处理中断。

高优先级的中断会立即被处理,而低优先级的中断则会被推迟到稍后处理。

linux系统中断详解

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等中断是需要保存出错码的。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

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"); // 遵循的协议///。

相关文档
最新文档