linux中断总结.doc_第1页
linux中断总结.doc_第2页
linux中断总结.doc_第3页
linux中断总结.doc_第4页
linux中断总结.doc_第5页
已阅读5页,还剩17页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1Linux中断的注册与释放:在, , 实现中断注册接口: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);函数参数说明unsigned int irq:所要注册的中断号irqreturn_t (*handler)(int, void *, struct pt_regs *):中断服务程序的入口地址。unsigned long flags:与中断管理有关的位掩码选项,有三组值:1. SA_INTERRUPT :快速中断处理程序,当使用它的是后处理器上所有的其他中断都被禁用。2. SA_SHIRQ :该中断是在设备之间可共享的3. SA_SAMPLE_RANDOM :这个位表示产生的中断能够有贡献给 /dev/random 和 /dev/urandom 使用的加密池.(此处不理解) const char *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_t short_interrupt(int irq, void *dev_id, struct pt_regs *regs)static long mytime=0;static int i=0;struct net_device *dev=(struct net_device *)dev_id;if(i=0)mytime=jiffies;elseif(iname,dev-irq);i ;return IRQ_HANDLED;这个函数实现的只是对两次发生中断的时间间隔的统计,时间单位是毫秒前言 在前面分析了中断的基本原理后,就可以写一个内核中断程序来体验以下,也可以借此程序继续深入来了解内核中断的执行过程 一.内核中断程序 : 我们还是来看一看成程序: 在看程序之前,要熟悉如何进行模块编程,和了解module_pararm()的用法。如果不熟悉的话请大家看,module_param()的学习 和Linux内核模块编程 ,在此不作解释。 1.程序interrupt.c 1 /* 2 *file name :interrupt.c 3 *atuthor : john 4 */ 5 #include 6 #include 7 #include 8 #include 9 10 MODULE_LICENSE(GPL); 11 static int irq; 12 char *interface; 13 static irqreturn_t myirq_handler(int irq,void *dev); 14 15 static int _init myirq_init(void) 16 17 printk(the module is working!n); 18 printk(the irq is ready for working!n); 19 if(request_irq(irq,myirq_handler,IRQF_SHARED,interface,&irq) 20 printk(KERN_ERR %s interrrupt cant register %d IRQ n,interface,irq); 21 return -EIO; 22 23 printk(%s request %d IRQn,interface,irq); 24 return 0; 25 26 static irqreturn_t myirq_handler(int irq,void *dev) 27 28 printk(%d IRQ is workingn,irq); 29 return IRQ_NONE; 30 31 static void _exit myirq_exit(void) 32 33 printk(the module is leaving!n); 34 printk(the irq is bye bye!n); 35 free_irq(irq,&irq); 36 printk(%s interrupt free %d IRQn,interface,irq); 37 38 39 module_init(myirq_init); 0 module_exit(myirq_exit); 41 module_param(interface,charp,0644); 42 module_param(irq,int,0644); 43 1 /* 2 *file name :interrupt.c 3 *atuthor : john 4 */ 5 #include 6 #include 7 #include 8 #include 9 10 MODULE_LICENSE(GPL); 11 static int irq; 12 char *interface; 13 static irqreturn_t myirq_handler(int irq,void *dev); 14 15 static int _init myirq_init(void) 16 17 printk(the module is working!n); 18 printk(the irq is ready for working!n); 19 if(request_irq(irq,myirq_handler,IRQF_SHARED,interface,&irq) 20 printk(KERN_ERR %s interrrupt cant register %d IRQ n,interface,irq); 21 return -EIO; 22 23 printk(%s request %d IRQn,interface,irq); 24 return 0; 25 26 static irqreturn_t myirq_handler(int irq,void *dev) 27 28 printk(%d IRQ is workingn,irq); 29 return IRQ_NONE; 30 31 static void _exit myirq_exit(void) 32 33 printk(the module is leaving!n); 34 printk(the irq is bye bye!n); 35 free_irq(irq,&irq); 36 printk(%s interrupt free %d IRQn,interface,irq); 37 38 39 module_init(myirq_init);40 module_exit(myirq_exit); 41 module_param(interface,charp,0644); 42 module_param(irq,int,0644); 43 2.Makefile的编写 1 obj-m:=tiger.o 2 3 CURRENT_PATH:=$(shell pwd) 4 VERSION_NUM:=$(shell uname -r) 5 LINUX_PATH:=/usr/src/linux-headers-$(VERSION_NUM) 6 7 8 all : 9 make -C $(LINUX_PATH) M=$(CURRENT_PATH) modules 10 clean: 11 make -C $(LINUX_PATH) M=$(CURRENT_PATH) clean 1 obj-m:=tiger.o 2 3 CURRENT_PATH:=$(shell pwd) 4 VERSION_NUM:=$(shell uname -r) 5 LINUX_PATH:=/usr/src/linux-headers-$(VERSION_NUM) 6 7 8 all : 9 make -C $(LINUX_PATH) M=$(CURRENT_PATH) modules 10 clean: 11 make -C $(LINUX_PATH) M=$(CURRENT_PATH) clean(程序的调试,加载和运行,在此不进行说明) 3.首先我们来分析下内核加载模块 在内核加载模块中最重要的的action就是注册中断处理程序。很明显,这一动作是通过request_irq()函数来完成的。 int request_irq(unsigned int irq, irq_handler_t handler,unsigned long flags, const char *devname, void *dev_id) A.先来分析形参: 第一个参数irq: 表示要分配的中断号。对于一些设备(系统时钟或键盘)它的值是预先固定的,而对于大多数设备来说,这个值是动态确定的。 第二个参数 handler: 表示要挂入到中断请求对列中的中断服务例程, 这个中断服务函数的原型是static irqreturn_t handler(int , void *); 中断处理程序的前缀为static,因为它从来不会被别的文件中的代码直接调用。 第三个参数flags:为标志位。可以取IRQF_DISABLED、IRQF_SHARED和IRQF_SAMPLE_RANDOM之一。在本实例程序中取 IRQF_SHARED,该标志表示多个中断处理程序共享irq中断线。一般某个中断线上的中断服务程序在执行时会屏蔽请求该线的其他中断,如果取 IRQF_DISABLED标志,则在执行该中断服务程序时会屏蔽所有其他的中断。取IRQF_SAMPLE_RANDOM则表示设备可以被看做是事件随见的发生源。 以下是官方解释: /* * These flags used only by the kernel as part of the * irq handling routines. * * IRQF_DISABLED - keep irqs disabled when calling the action handler * IRQF_SAMPLE_RANDOM - irq is used to feed the random generator * IRQF_SHARED - allow sharing the irq among several devices * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur * IRQF_TIMER - Flag to mark this interrupt as timer interrupt * IRQF_PERCPU - Interrupt is per cpu * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is * registered first in an shared interrupt is considered for * performance reasons) */ #define IRQF_DISABLED 0x00000020 #define IRQF_SAMPLE_RANDOM 0x00000040 #define IRQF_SHARED 0x00000080 #define IRQF_PROBE_SHARED 0x00000100 #define IRQF_TIMER 0x00000200 #define IRQF_PERCPU 0x00000400 #define IRQF_NOBALANCING 0x00000800 #define IRQF_IRQPOLL 0x00001000 /* * These flags used only by the kernel as part of the * irq handling routines. * * IRQF_DISABLED - keep irqs disabled when calling the action handler * IRQF_SAMPLE_RANDOM - irq is used to feed the random generator * IRQF_SHARED - allow sharing the irq among several devices * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur * IRQF_TIMER - Flag to mark this interrupt as timer interrupt * IRQF_PERCPU - Interrupt is per cpu * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is * registered first in an shared interrupt is considered for * performance reasons) */ #define IRQF_DISABLED 0x00000020 #define IRQF_SAMPLE_RANDOM 0x00000040 #define IRQF_SHARED 0x00000080 #define IRQF_PROBE_SHARED 0x00000100 #define IRQF_TIMER 0x00000200 #define IRQF_PERCPU 0x00000400 #define IRQF_NOBALANCING 0x00000800 #define IRQF_IRQPOLL 0x00001000 第四个参数devname:是请求中断的设备的名称。当你加载模块成功后可以在/proc/interrupts中查看到具体设备的名称,与此同时也可以看到这个设备对应的中断号以及请求次数。 第五个参数dev_id:为一个指针型变量。注意该参数为void型,也就是说通过强制转换可以转换为任意类型。dev_id主要用于共享中断线,对每个注册的中断处理程序来说,( Dev_id must be globally unique. Normally the address of the device data structure is used as the cookie.)dev_id参数必须唯一(指向任一设备结构的指针就可以满足此要求,选择设备结构因为它是唯一的,而且中断处理程序可能会用到它)如果无需共享中断线,则将该参数赋值为NULL。 B:函数返回值 requset_irq()函数成功执行后返回0。如果返回非0值,就表示错误发生。此时,指定的中断处理程序不会被注册。这里面有几个疑问: 为什么要注册中断函数 共享中断线的概念,参数dev_id的作用是什么 看一个图进行说明: 1由图可知:有16个中断线。要使用中断线,就要进行中断线的 申请 ,也常把申请一条中断线称为申请一个中断号,这就 与request_irq()函数中的第一个形参 irq 有关系 。 2Linux有256个中断向量,而外部中中断向量只有16个(3247)。由于硬件上的限制,很多外部设备不得不共享中断线。 (例如:一些PC机所用的网卡和图形卡可以把它们分配到一条中断线上) 让每个中断源独自占用一条中断线是不实现的。 3共享中断线的话虽然解决了中断资源的问题,但是,此时引出了另一个问题( 任何事物都有其两面性 ),此时仅仅用中断描述符并不能提供中断产生的所有信息。为了解决这个问题,内核必须对中断线给出近一步的描述,所以在Linux设计中,为每个中断请求IRQ设置了一个专用队列(中断请求队列) 。4中断服例程序和中断处理程序的区别:a.中断服务例程(interrupt service routine): Linux中,15条中断线对应15个中断处理程序,依次命名是IRQ0x00_interrupt(),IRQ0x01_interrupt(). IRQ0X1f_interrupt(). 中断处理程序相当于某个中断向量的总处理程序。 eg:IRQ0X05_interupt()是5号中断(向量为37)的总处理程序。 b.中断服务例程是针对一个具体设备的中断。5.注册中断服务例程:在IDT表完成初始化时,每个中断服务队列还为空。此时即使打开中断且某个外设的中断真的发生了,也得不到实际的服务。因为CPU虽然通过中断门进入了某个中断向量的总处理程序。但是,具体的中断服务例程还没有挂入中断请求队列。所以,在设备驱动程序的初始化阶段,必须通过request_irq()函数将响应的中断服务例程挂入中断请求队列,也就是进行注册。 6分析一下中断服务程序,即request_irq()函数中第二个参数所对应的函数 static irqreturn_t myirq_handler(int irq,void *dev_id) printk(ISR is Workingn); return IRQ_HANDLED; 中断服务例程的形参: irq :中断号。b.void *dev_id :与request_irq()的参数dev_id一致,可以根据这个设备id号得到相应设备的数据结构,进而得到相应设备的信息和相关数据。c.返回值:中断程序的返回值是一个特殊类型 rqreturn_t。但是中断程序的返回值却只有两个值IRQ_NONE和IRQ_HANDLED。IRQ_NONE:中断程序接收到中断信号后发现这并不是注册时指定的中断原发出的中断信号。IRQ_HANDLED:接收到了准确的中断信号,并且作了相应正确的处理。一般 中断处理程序要做什么service,主要取决于产生的设备和该设备为什么要发送中断。 John哥说明: 1.当一个给定的中断处理程序正在执行时,这条中断线上的其它中断都会被屏蔽。but,所有其他中断线上的中断都是打开的。因此这些不同中断线上的其他中断都能被处理。 2.request_irq()函数可能会睡眠,所以,不能在中断上下文或其它不允许阻塞的代码中调用该函数。 4.在深入分析request_irq()函数之前,先来看几个重要的数据结构。 A.irqaction的数据结构(用irqaction结构体来描述一个具体的中断服务例程) 113struct irqaction 114 irq_handler_t handler; 115 unsigned long flags; 116 const char *name; 117 void *dev_id; 118 struct irqaction *next; 119 int irq; 120 struct proc_dir_entry *dir; 121 irq_handler_t thread_fn; 122 struct task_struct *thread; 123 unsigned long thread_flags; 124; 125 113struct irqaction 114 irq_handler_t handler; 115 unsigned long flags; 116 const char *name; 117 void *dev_id; 118 struct irqaction *next; 119 int irq; 120 struct proc_dir_entry *dir; 121 irq_handler_t thread_fn; 122 struct task_struct *thread; 123 unsigned long thread_flags; 124; 125 1handler:指向具体的一个中断服务例程。 2flags:表示中断标志位,对应于request_irq()函数中所传递的第三个参数,可取IRQF_DISABLED、IRQF_SAMPLE_RANDOM和IRQF_SHARED其中之一。 3name:请求中断的设备名称,对应request_irq()函数中所传递的第四个参数 4dev_id: 共享中断时有用。 对应于request_irq()函数中所传递的第五个参数,可取任意值,但必须唯一能够代表发出中断请求的设备,通常取描述该设备的结构体。 5strct irqaction *next:指向irqaction描述符的下一个元素。用一条链表将共享同一条中断线上的中断服务例程链接起来。 6irq:所申请的中断号 7dir:指向proc/irq/NN/name entry 8thread_fn:指向具体的一个线程化的中断。 9thread:指向线程中断的指针。 10thread_flags:线程中断的标志。B.irq_desc的数据结构体 每个中断向量都有它自己的irq_desc 描述符。即用irq_desc来描述中断向量。所有的这些中断描述符组织在一起就形成了irq_desc irq_descNR_IRQS数组175struct irq_desc 176 unsigned int irq; 177 struct timer_rand_state *timer_rand_state; 178 unsigned int *kstat_irqs; 179#ifdef CONFIG_INTR_REMAP 180 struct irq_2_iommu *irq_2_iommu; 181#endif 182 irq_flow_handler_t handle_irq; 183 struct irq_chip *chip; 184 struct msi_desc *msi_desc; 185 void *handler_data; 186 void *chip_data; 187 struct irqaction *action; /* IRQ action list */ 188 unsigned int status; /* IRQ status */ 189 190 unsigned int depth; /* nested irq disables */ 191 unsigned int wake_depth; /* nested wake enables */ 192 unsigned int irq_count; /* For detecting broken IRQs */ 193 unsigned long last_unhandled; /* Aging timer for unhandled count */ 194 unsigned int irqs_unhandled; 195 raw_spinlock_t lock; 196#ifdef CONFIG_SMP 197 cpumask_var_t affinity; 198 const struct cpumask *affinity_hint; 199 unsigned int node; 200#ifdef CONFIG_GENERIC_PENDING_IRQ 201 cpumask_var_t pending_mask; 202#endif 203#endif 204 atomic_t threads_active; 205 wait_queue_head_t wait_for_threads; 206#ifdef CONFIG_PROC_FS 207 struct proc_dir_entry *dir; 208#endif 209 const char *name; 210 _cacheline_internodealigned_in_smp; 211 212extern void arch_init_copy_chip_data(struct irq_desc *old_desc, 213 struct irq_desc *desc, int node); 214extern void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc); 215 216#ifndef CONFIG_SPARSE_IRQ 217extern struct irq_desc irq_descNR_IRQS; 175struct irq_desc 176 unsigned int irq; 177 struct timer_rand_state *timer_rand_state; 178 unsigned int *kstat_irqs; 179#ifdef CONFIG_INTR_REMAP 180 struct irq_2_iommu *irq_2_iommu; 181#endif 182 irq_flow_handler_t handle_irq; 183 struct irq_chip *chip; 184 struct msi_desc *msi_desc; 185 void *handler_data; 186 void *chip_data; 187 struct irqaction *action; /* IRQ action list */ 188 unsigned int status; /* IRQ status */ 189 190 unsigned int depth; /* nested irq disables */ 191 unsigned int wake_depth; /* nested wake enables */ 192 unsigned int irq_count; /* For detecting broken IRQs */ 193 unsigned long last_unhandled; /* Aging timer for unhandled count */ 194 unsigned int irqs_unhandled; 195 raw_spinlock_t lock; 196#ifdef CONFIG_SMP 197 cpumask_var_t affinity; 198 const struct cpumask *affinity_hint; 199 unsigned int node; 200#ifdef CONFIG_GENERIC_PENDING_IRQ 201 cpumask_var_t pending_mask; 202#endif 203#endif 204 atomic_t threads_active; 205 wait_queue_head_t wait_for_threads; 206#ifdef CONFIG_PROC_FS 207 struct proc_dir_entry *dir; 208#endif 209 const char *name; 210 _cacheline_internodealigned_in_smp; 211 212extern void arch_init_copy_chip_data(struct irq_desc *old_desc, 213 struct irq_desc *desc, int node); 214extern void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc); 215 216#ifndef CONFIG_SPARSE_IRQ 217extern struct irq_desc irq_descNR_IRQS; 1irq:表示这个描述符所对应的中断号。 2handle_irq:指向该IRQ线的公共服务程序(即该IRQ所对应的中断处理程序。 3chip:它是一个struct irq_chip类型的指针,是中断控制器的描述符 。在2.6以前的版本中它是hw_irq_controller。4handler_data:是handler_irq的参数。5chip_data:是指向irq_chip的指针。6atcion:一个struct irqaction类型的指针,它指向一个单链表。该链表是由该中断线上所有中断服务例程链接起来的。7status:表示中断线当前的状态。8depth:中断线被激活时,值为0;当值为正数时,表示被禁止的次数。9irq_count:表示该中断线上发生中断的次数10irqs_unhandled:该IRQ线上未处理中断发生的次数11name:申请中断设备的名字。 C.struct irq_chip结构体: struct irq_chip是一个中断控制器的描述符。Linux支持N种可编程中断控制器PIC(中断控制器),通常不同的体系结构就有一套自己的中断处理方式。内核为了统一的处理中断,提供了底层的中断处理抽象接口,对于每个平台都需要实现底层的接口函数。这样对于上层的中断通用处理程序就无需任何改动。 struct irq_chip的具体代码如下: 111struct irq_chip 112 const char *name; 113 unsigned int (*startup)(unsigned int irq); 114 void (*shutdown)(unsigned int irq); 115 void (*enable)(unsigned int irq); 116 void (*disable)(unsigned int irq); 117 118 void (*ack)(unsigned int irq); 119 void (*mask)(unsigned int irq); 120 void (*mask_ack)(unsigned int irq); 121 void (*unmask)(unsigned int irq); 122 void (*eoi)(unsigned int irq); 123 124 void (*end)(unsigned int irq); 125 int (*set_affinity)(unsigned int irq, 126 const struct cpumask *dest); 127 int (*retrigger)(unsigned int irq); 128 int (*set_type)(unsigned int irq, unsigned int flow_type); 129 int (*set_wake)(unsigned int irq, unsigned int on); 130 131 void (*bus_lock)(unsigned int irq); 132 void (*bus_sync_unlock)(unsigned int irq); 133 134 /* Currently used only by UML, might disappear one day.*/ 135#ifdef CONFIG_IRQ_RELEASE_METHOD 136 void (*release)(unsigned int irq, void *dev_id); 137#endif 138 /* 139 * For compatibility, -typename is copied into -name. 140 * Will disappear. 1

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论