1.Linux中断的注册与释放:在linux/interrupt.h,,实现中断注册接口:intrequest_irq(unsignedintirq,irqreturn_t(*handler)(int,void*,structpt_regs*),unsignedlongflags,constchar*dev_name,void*dev_id);voidfree_irq(unsignedintirq,void*dev_id);函数参数说明unsignedintirq:所要注册的中断号irqreturn_t(*handler)(int,void*,structpt_regs*):中断服务程序的入口地址。unsignedlongflags:与中断管理有关的位掩码选项,有三组值:1.SA_INTERRUPT:快速中断处理程序,当使用它的是后处理器上所有的其他中断都被禁用。2.SA_SHIRQ:该中断是在设备之间可共享的3.SA_SAMPLE_RANDOM:这个位表示产生的中断能够有贡献给/dev/random和/dev/urandom使用的加密池.(此处不理解)constchar*dev_name:设备描述,表示那一个设备在使用这个中断。void*dev_id:用作共享中断线的指针.它是一个独特的标识,用在当释放中断线时以及可能还被驱动用来指向它自己的私有数据区(来标识哪个设备在中断)。这个参数在真正的驱动程序中一般是指向设备数据结构的指针.在调用中断处理程序的时候它就会传递给中断处理程序的void*dev_id。(这是我的理解)如果中断没有被共享,dev_id可以设置为NULL,但是使用这个项指向设备结构不管如何是个好主意.我们将在实现一个处理一节中看到dev_id的一个实际应用。中断号的查看可以使用下面的命令:“cat/proc/interrupts”。/proc/stat记录了几个关于系统活动的低级统计量,包括(但是不限于)自系统启动以来收到的中断数.stat的每一行以一个文本字串开始,是该行的关键词;intr标志是我们在找的.第一个数是所有中断的总数,而其他每一个代表一个单个IRQ线,从中断0开始.所有的计数跨系统中所有处理器而汇总的.这个快照显示,中断号4已使用1次,尽管当前没有安装处理.如果你在测试的驱动请求并释放中断在每个打开和关闭循环,你可能发现/proc/stat比/proc/interrupts更加有用.以下是一个统计中断时间间隔的中断服务程序。irqreturn_tshort_interrupt(intirq,void*dev_id,structpt_regs*regs){staticlongmytime=0;staticinti=0;structnet_device*dev=(structnet_device*)dev_id;if(i==0){mytime=jiffies;}elseif(i20){mytime=jiffies-mytime;printk(RequestonIRQ%dtime%d\n,irq,mytime);mytime=jiffies;printk(Interrupton%s-----%d\n,dev-name,dev-irq);}i;returnIRQ_HANDLED;}这个函数实现的只是对两次发生中断的时间间隔的统计,时间单位是毫秒前言在前面分析了中断的基本原理后,就可以写一个内核中断程序来体验以下,也可以借此程序继续深入来了解内核中断的执行过程一.内核中断程序:我们还是来看一看成程序:在看程序之前,要熟悉如何进行模块编程,和了解module_pararm()的用法。如果不熟悉的话请大家看,module_param()的学习和Linux内核模块编程,在此不作解释。1.程序interrupt.c1/*2*filename:interrupt.c3*atuthor:john4*/5#includelinux/init.h6#includelinux/module.h7#includelinux/kernel.h8#includelinux/interrupt.h910MODULE_LICENSE(GPL);11staticintirq;12char*interface;13staticirqreturn_tmyirq_handler(intirq,void*dev);1415staticint__initmyirq_init(void)16{17printk(themoduleisworking!\n);18printk(theirqisreadyforworking!\n);19if(request_irq(irq,myirq_handler,IRQF_SHARED,interface,&irq)){20printk(KERN_ERR%sinterrruptcan'tregister%dIRQ\n,interface,irq);21return-EIO;22}23printk(%srequest%dIRQ\n,interface,irq);24return0;25}26staticirqreturn_tmyirq_handler(intirq,void*dev)27{28printk(%dIRQisworking\n,irq);29returnIRQ_NONE;30}31staticvoid__exitmyirq_exit(void)32{33printk(themoduleisleaving!\n);34printk(theirqisbyebye!\n);35free_irq(irq,&irq);36printk(%sinterruptfree%dIRQ\n,interface,irq);3738}39module_init(myirq_init);0module_exit(myirq_exit);41module_param(interface,charp,0644);42module_param(irq,int,0644);431/*2*filename:interrupt.c3*atuthor:john4*/5#includelinux/init.h6#includelinux/module.h7#includelinux/kernel.h8#includelinux/interrupt.h910MODULE_LICENSE(GPL);11staticintirq;12char*interface;13staticirqreturn_tmyirq_handler(intirq,void*dev);1415staticint__initmyirq_init(void)16{17printk(themoduleisworking!\n);18printk(theirqisreadyforworking!\n);19if(request_irq(irq,myirq_handler,IRQF_SHARED,interface,&irq)){20printk(KERN_ERR%sinterrruptcan'tregister%dIRQ\n,interface,irq);21return-EIO;22}23printk(%srequest%dIRQ\n,interface,irq);24return0;25}26staticirqreturn_tmyirq_handler(intirq,void*dev)27{28printk(%dIRQisworking\n,irq);29returnIRQ_NONE;30}31staticvoid__exitmyirq_exit(void)32{33printk(themoduleisleaving!\n);34printk(theirqisbyebye!\n);35free_irq(irq,&irq);36printk(%sinterruptfree%dIRQ\n,interface,irq);3738}39module_init(myirq_init);40module_exit(myirq_exit);41module_param(interface,charp,0644);42module_param(irq,int,0644);432.Makefile的编写1obj-m:=tiger.o23CURRENT_PATH:=$(shellpwd)4VERSION_NUM:=$(shelluname-r)5LINUX_PATH:=/usr/src/linux-headers-$(VERSION_NUM)678all:9make-C$(LINUX_PATH)M=$(CURRENT_PATH)modules10clean:11make-C$(LINUX_PATH)M=$(CURRENT_PATH)clean1obj-m:=tiger.o23CURRENT_PATH:=$(shellpwd)4VERSION_NUM:=$(shelluname-r)5LINUX_PATH:=/usr/src/linux-headers-$(VERSION_NUM)678all:9make-C$(LINUX_PATH)M=$(CURRENT_PATH)modules10clean:11make-C$(LINUX_PATH)M=$(CURRENT_PATH)clean(程序的调试,加载和运行,在此不进行说明)3.首先我们来分析下内核加载模块在内核加载模块中最重要的的action就是注册中断处理程序。很明显,这一动作是通过request_irq()函数来完成的。intrequest_irq(unsignedintirq,irq_handler_thandler,unsignedlongflags,constchar*devname,void*dev_id)A.先来分析形参:第一个参数irq:表示要分配的中断号。对于一些设备(系统时钟或键盘)它的值是预先固定的,而对于大多数设备来说,这个值是动态确定的。第二个参数handler:表示要挂入到中断请求对列中的中断服务例程,这个中断服务函数的原型是staticirqreturn_thandler(int,void*);中断处理程序的前缀为static,因为它从来不会被别的文件中的代码直接调用。第三个参数flags:为标志位。可以取IRQF_DISABLED、IRQF_SHARED和IRQF_SAMPLE_RANDOM之一。在本实例程序中取IRQF_SHARED,该标志表示多个中断处理程序共享irq中断线。一般某个中断线上的中断服务程序在执行时会屏蔽请求该线的其他中断,如果取IRQF_DISABLED标志,则在执行该中断服务程序时会屏蔽所有其他的中断。取IRQF_SAMPLE_RANDOM则表示设备可以被看做是事件随见的发生源。以下是官方解释:/**Theseflagsusedonlybythekernelaspartofthe*irqhandlingroutines.**IRQF_DISABLED-keepirqsdisabledwhencallingtheactionhandler*IRQF_SAMPLE_RANDOM-irqisusedtofeedtherandomgenerator*IRQF_SHARED-allowsharingtheirqamongseveraldevices*IRQF_PROBE_SHARED-setbycallerswhentheyexpectsharingmismatchestooccur*IRQF_TIMER-Flagtomarkthisinterruptastimerinterrupt*IRQF_PERCPU-Interruptispercpu*IRQF_NOBALANCING-Flagtoexcludethisinterruptfromirqba