第一篇:linux中断总结
1.Linux中断的注册与释放:
在
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; }else if(i<20){ mytime =jiffies-mytime;printk(“Request on IRQ %d time %dn”,irq , mytime);mytime=jiffies; printk(“Interrupt on %s-----%d n”,dev->name,dev->irq);} i;return IRQ_HANDLED;} 这个函数实现的只是对两次发生中断的时间间隔的统计,时间单位是毫秒
前言
在前面分析了中断的基本原理后,就可以写一个内核中断程序来体验以下,也可以借此程序继续深入来了解内核中断的执行过程 一.内核中断程序 :
我们还是来看一看成程序:
在看程序之前,要熟悉如何进行模块编程,和了解module_pararm()的用法。如果不熟悉的话请大家看,module_param()的学习和Linux内核模块编程,在此不作解释。1.程序interrupt.c /* 2 *file name :interrupt.c 3 *atuthor : john 4 */ 5 #include
printk(KERN_ERR “%s interrrupt can't 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
printk(KERN_ERR “%s interrrupt can't register %d 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)
IRQ 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_DISABLEDirq is used to feed the random generator * IRQF_SHAREDset by callers when they expect sharing mismatches to occur * IRQF_TIMERInterrupt is per cpu * IRQF_NOBALANCINGInterrupt 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_DISABLEDirq is used to feed the random generator * IRQF_SHAREDset by callers when they expect sharing mismatches to occur * IRQF_TIMERInterrupt is per cpu * IRQF_NOBALANCINGInterrupt 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 有关系。2>Linux有256个中断向量,而外部中中断向量只有16个(32~47)。由于硬件上的限制,很多外部设备不得不共享中断线。
(例如:一些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;} 中断服务例程的形参: a.int 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
1>handler:指向具体的一个中断服务例程。
2>flags:表示中断标志位,对应于request_irq()函数中所传递的第三个参数,可取IRQF_DISABLED、IRQF_SAMPLE_RANDOM和IRQF_SHARED其中之一。
3>name:请求中断的设备名称,对应request_irq()函数中所传递的第四个参数
4>dev_id: 共享中断时有用。对应于request_irq()函数中所传递的第五个参数,可取任意值,但必须唯一能够代表发出中断请求的设备,通常取描述该设备的结构体。5>strct irqaction *next:指向irqaction描述符的下一个元素。用一条链表将共享同一条中断线上的中断服务例程链接起来。
6>irq:所申请的中断号
7>dir:指向proc/irq/NN/name entry
8>thread_fn:指向具体的一个线程化的中断。
9>thread:指向线程中断的指针。
10>thread_flags:线程中断的标志。
B.irq_desc的数据结构体 每个中断向量都有它自己的irq_desc 描述符。即用irq_desc来描述中断向量。所有的这些中断描述符组织在一起就形成了irq_desc irq_desc[NR_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_desc[NR_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_desc[NR_IRQS];
1>irq:表示这个描述符所对应的中断号。
2>handle_irq:指向该IRQ线的公共服务程序(即该IRQ所对应的中断处理程序。
3>chip:它是一个struct irq_chip类型的指针,是中断控制器的描述符。在2.6以前的版本中它是hw_irq_controller。
4>handler_data:是handler_irq的参数。5>chip_data:是指向irq_chip的指针。6>atcion:一个struct irqaction类型的指针,它指向一个单链表。该链表是由该中断线上所有中断服务例程链接起来的。7>status:表示中断线当前的状态。
8>depth:中断线被激活时,值为0;当值为正数时,表示被禁止的次数。9>irq_count:表示该中断线上发生中断的次数
10>irqs_unhandled:该IRQ线上未处理中断发生的次数 11>name:申请中断设备的名字。
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.141 */ 142 const char *typename;143};144 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.141 */ 142 const char *typename;143};144
name:中断控制器的名字; Startup:启动中断线; Shutdown:关闭中断线; Enable:允许中断; Disable:禁止中断;
分析了struct irq_desc,struct irq_chip和irqaction的数据结构之后我们来看看他们之间的关系。
现在深入分析request_irq()内部是如何实现的。
135request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, 136 const char *name, void *dev)137{ 138 return request_threaded_irq(irq, handler, NULL, flags, name, dev);139} 140 135request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, 136 const char *name, void *dev)137{ 138 return request_threaded_irq(irq, handler, NULL, flags, name, dev);139} 140
可以看到request_irq()函数里面有封装了request_threaded_irq(irq, handler, NULL, flags, name, dev)函数。
先看一下官方的解释
1006/** 1007 * request_threaded_irqallocate an interrupt line 1008 * @irq: Interrupt line to allocate 1009 * @handler: Function to be called when the IRQ occurs.1010 * Primary handler for threaded interrupts 1011 * If NULL and thread_fn!= NULL the default 1012 * primary handler is installed 1013 * @thread_fn: Function called from the irq handler thread 1014 * If NULL, no irq thread is created 1015 * @irqflags: Interrupt type flags 1016 * @devname: An ascii name for the claiming device 1017 * @dev_id: A cookie passed back to the handler function 1018 * 1019 * This call allocates interrupt resources and enables the 1020 * interrupt line and IRQ handling.From the point this 1021 * call is made your handler function may be invoked.Since 1022 * your handler function must clear any interrupt the board 1023 * raises, you must take care both to initialise your hardware 1024 * and to set up the interrupt handler in the right order.1025 * 1026 * If you want to set up a threaded irq handler for your device 1027 * then you need to supply @handler and @thread_fn.@handler ist 1028 * still called in hard interrupt context and has to check 1029 * whether the interrupt originates from the device.If yes it 1030 * needs to disable the interrupt on the device and return 1031 * IRQ_WAKE_THREAD which will wake up the handler thread and run 1032 * @thread_fn.This split handler design is necessary to support 1033 * shared interrupts.1034 * 1035 * Dev_id must be globally unique.Normally the address of the 1036 * device data structure is used as the cookie.Since the handler 1037 * receives this value it makes sense to use it.1038 * 1039 * If your interrupt is shared you must pass a non NULL dev_id 1040 * as this is required when freeing the interrupt.1041 * 1042 * Flags: 1043 * 1044 * IRQF_SHARED Interrupt is shared 1045 * IRQF_SAMPLE_RANDOM The interrupt can be used for entropy 1046 * IRQF_TRIGGER_* Specify active edge(s)or level 1047 * 1048 */
5.首先分析request_threaded_irq()函数中的各个形参 1>:irq:表示申请的中断号。2>:handler:表示中断服务例程
3.> thread_fn:中断线程化,此处传递的是NULL。NULL表示没有中断线程化。此参数是最新版本中才出现的。为什么要提出中断线程化? 在 Linux 中,中断具有最高的优先级。不论在任何时刻,只要产生中断事件,内核将立即执行相应的中断 处理程序,等到所有挂起的中断和软中断处理完毕后才能执行正常的任务,因此有可能造成实时任务得不
到及时的处理。中断线程化之后,中断将作为内核线程运行而且被赋予不同的实时优先级,实时任务可以
有比中断线程更高的优先级。这样,具有最高优先级的实时任务就能得到优先处理,即使在严重负载下仍
有实时性保证。but,并不是所有的中断都可以被线程化,比如时钟中断,主要用来维护系统时间以及定时器 等,其中定时器是操作系统的脉搏,一旦被线程化,就有可能被挂起,这样后果将不堪设想,所以不应当 被线程化。
4>.irqflags:表示中断标志位。
5>.devname:表示请求中断的设备的名称。
6>.dev_id: 对应于request_irq()函数中所传递的第五个参数,可取任意值,但必须唯一能够代表发出中断请求的设备,通常取描述该设备的结构体。共享中断时所用。现在继续迭代深入 request_threaded_irq()内部是如何实现的。
1049int request_threaded_irq(unsigned int irq, irq_handler_t handler, 1050 irq_handler_t thread_fn, unsigned long irqflags, 1051 const char *devname, void *dev_id)1052{ 1053 struct irqaction *action;1054 struct irq_desc *desc;1055 int retval;1056 1057 /* 1058 * Sanity-check: shared interrupts must pass in a real dev-ID, 1059 * otherwise we'll have trouble later trying to figure out 1060 * which interrupt is which(messes up the interrupt freeing 1061 * logic etc).1062 */ 1063 if((irqflags & IRQF_SHARED)&&!dev_id)1064 return-EINVAL;1065 1066 desc = irq_to_desc(irq);1067 if(!desc)1068 return-EINVAL;1069 1070 if(desc->status & IRQ_NOREQUEST)1071 return-EINVAL;1072 1073 if(!handler){ 1074 if(!thread_fn)1075 return-EINVAL;1076 handler = irq_default_primary_handler;1077 } 1078 1079 action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);1080 if(!action)1081 return-ENOMEM;1082 1083 action->handler = handler;1084 action->thread_fn = thread_fn;1085 action->flags = irqflags;1086 action->name = devname;1087 action->dev_id = dev_id;1088 1089 chip_bus_lock(irq, desc);1090 retval = __setup_irq(irq, desc, action);1091 chip_bus_sync_unlock(irq, desc);1092 1093 if(retval)1094 kfree(action);1095 1096#ifdef CONFIG_DEBUG_SHIRQ 1097 if(!retval &&(irqflags & IRQF_SHARED)){ 1098 /* 1099 * It's a shared IRQ--the driver ought to be prepared for it 1100 * to happen immediately, so let's make sure....1101 * We disable the irq to make sure that a 'real' IRQ doesn't 1102 * run in parallel with our fake.1103 */ 1104 unsigned long flags;1105 1106 disable_irq(irq);1107 local_irq_save(flags);1108 1109 handler(irq, dev_id);1110 1111 local_irq_restore(flags);1112 enable_irq(irq);1113 } 1114#endif 1115 return retval;1116} 1049int request_threaded_irq(unsigned int irq, irq_handler_t handler, 1050 irq_handler_t thread_fn, unsigned long irqflags, 1051 const char *devname, void *dev_id)1052{ 1053 struct irqaction *action;1054 struct irq_desc *desc;1055 int retval;1056 1057 /* 1058 * Sanity-check: shared interrupts must pass in a real dev-ID, 1059 * otherwise we'll have trouble later trying to figure out 1060 * which interrupt is which(messes up the interrupt freeing 1061 * logic etc).1062 */ 1063 if((irqflags & IRQF_SHARED)&&!dev_id)1064 return-EINVAL;1065 1066 desc = irq_to_desc(irq);1067 if(!desc)1068 return-EINVAL;1069 1070 if(desc->status & IRQ_NOREQUEST)1071 return-EINVAL;1072 1073 if(!handler){ 1074 if(!thread_fn)1075 return-EINVAL;1076 handler = irq_default_primary_handler;1077 } 1078 1079 action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);1080 if(!action)1081 return-ENOMEM;1082 1083 action->handler = handler;1084 action->thread_fn = thread_fn;1085 action->flags = irqflags;1086 action->name = devname;1087 action->dev_id = dev_id;1088 1089 chip_bus_lock(irq, desc);1090 retval = __setup_irq(irq, desc, action);1091 chip_bus_sync_unlock(irq, desc);1092 1093 if(retval)1094 kfree(action);1095 1096#ifdef CONFIG_DEBUG_SHIRQ 1097 if(!retval &&(irqflags & IRQF_SHARED)){ 1098 /* 1099 * It's a shared IRQ--the driver ought to be prepared for it 1100 * to happen immediately, so let's make sure....1101 * We disable the irq to make sure that a 'real' IRQ doesn't 1102 * run in parallel with our fake.1103 */ 1104 unsigned long flags;1105 1106 disable_irq(irq);1107 local_irq_save(flags);1108 1109 handler(irq, dev_id);1110 1111 local_irq_restore(flags);1112 enable_irq(irq);1113 } 1114#endif 1115 return retval;1116}
程序的第一行和第二行分别定义了:
(1)struct irqaction *action;
(2)2struct irq_desc *desc;
两个指针action和desc,它们分别指向了结构体irqaction和 irq_desc。
(3)if((irqflags & IRQF_SHARED)&&!dev_id)return-EINVAL;
作用是:判断中断标志位,如果是共享中断的话就必须要有一个唯一的dev_id,否则返回一个错误。
(4)desc = irq_to_desc(irq);
irq_to_desc(irq):根据中断号irq在 irq_desc[NR_IRQS]数组中 返回一个具体的irq_desc。即根据irq找到它的中断处理程序。
(5)if(!desc)
return-EINVAL;
当返回一个空值时返回一个错误。说明申请中断号失败。
(6)if(desc->status & IRQ_NOREQUEST)return-EINVAL;
判断中断线的状态,若为IRQ_NOREQUEST时(IRQ_NOREQUEST表示 IRQ 不能被申请)
(7)if(!handler){ if(!thread_fn)return-EINVAL;handler = irq_default_primary_handler;}
判断中断服务例程是否为空,如果handler为空,则判断线程中断服务例程,若线程中断服务例程也为空,则返回一个错误值。否则中断服务例程指向: rq_default_primary_handler。
(8)
1079 action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);1080 if(!action)1081 return-ENOMEM;1082 1083 action->handler = handler;1084 action->thread_fn = thread_fn;1085 action->flags = irqflags;1086 action->name = devname;1087 action->dev_id = dev_id;
从1079~1087:根据requst_irq()函数中传递的参数生成一个irqaction.1097 if(!retval &&(irqflags & IRQF_SHARED)){ 1098 /* 1099 * It's a shared IRQ--the driver ought to be prepared for it 1100 * to happen immediately, so let's make sure....1101 * We disable the irq to make sure that a 'real' IRQ doesn't 1102 * run in parallel with our fake.1103 */ 1104 unsigned long flags;1105 1106 disable_irq(irq);1107 local_irq_save(flags);1108 1109 handler(irq, dev_id);1110 1111 local_irq_restore(flags);1112 enable_irq(irq);1113 }
1097~1113:如果为共享中断的话,在执行中断服务例程之前,要先把这条中断线上的中断屏蔽,让后在执行,执行完之后打开中断。
6.有注册中断服务函数,那必然有相应的释放中断函数。
可以调用void free_irq(unsigned int irq, void *dev_id)来释放我们申请的中断线。
函数形参:
1>unsigned int riq:表示申请的中断号与request_irq()函数中的第一个形参对应。
2>void *dev_id:与request_irq()函数中的最后一个形参含义和用法相同,在此不再说明。
函数功能:
如果指定的中断线不是共享的,那么,该函数删除处理程序的同时将禁用这条中断线。如果中断线是共享的,则仅删除dev_id所对应的处理程序,而这条中断线本省只有在删除了最后一个处理程序时才会被禁止。
切记:This function must not be called from interrupt context
freee_irq()函数不能在中断上下文中被调用。
3>深入分析下free_irq()函数内部是如何实现的
993void free_irq(unsigned int irq, void *dev_id)994{ 995 struct irq_desc *desc = irq_to_desc(irq);996 997 if(!desc)998 return;999 1000 chip_bus_lock(irq, desc);1001 kfree(__free_irq(irq, dev_id));1002 chip_bus_sync_unlock(irq, desc);1003} 993void free_irq(unsigned int irq, void *dev_id)994{ 995 struct irq_desc *desc = irq_to_desc(irq);996 997 if(!desc)998 return;999 1000 chip_bus_lock(irq, desc);1001 kfree(__free_irq(irq, dev_id));1002 chip_bus_sync_unlock(irq, desc);1003} 可以看到free_irq()函数了封装了_free_irq(irq,dev_id)函数。free_irq()调用_free_irq()把每一个具体的中断服务例程()释放。
本篇文章来源于 Linux公社网站(原文链接:
第二篇:嵌入式linu学习心得
嵌入式Linux学习心得
1、Linux命令
ls:查看目录-l以列表方式查看;ls –l 与ll的功能一样 pwd: 查看当前的目录
cd:改变当前操作目录cd /直接跳到根目录 cd..回到上一级目录 cat: 打印显示当前文件的内容信息
mkdir:创建目录
fdisk: 查看硬盘分区信息,-l以列表方式查看
->代表是链接文件,类似window下的快捷方式。
cp: 复制命令,例子cp 文件名 /home/dir/
mv: 移动或改名,如mv sonf.confsonf.txt(改名)移动:mv sonf.conf / rm:删除命令,如rm –f test.c;如删除目录rm –fr d
man:查看某个命令的帮助,man 命令
2、各系统目录的功能
drw—r—w--:d代表是目录,drw代表当前用户的权限,r代表组用户的权限,w代表其它用户的权限。x代表有执行权限。
/boot/gruff.conf: 启动引导程序
/dev:brw—rw--:b代表是块设备。Linux设备有三种,块设备(b开头)、字符设备(c开头)、网络设备。had代表第一个硬盘,hdb代表第二个硬盘。Hdb2代表第二块硬盘的第二个分区。3,67代表主设备为3,从设备为67./etc:存放的是系统的配置文件。Inittab文件存放不同启动方式下必须启动的进程。Inittab文件中有6个启动level,wait中对应着6个level的目录,respawn代表当一个进程被意外终止了,但会自动启动的进程,如守护进程。rc.d目录中存放了一个rc.sysinit文件,里面存放系统初始化配置信息。/etc还有一个vsftpd里面存放tcp、ftp的配置。
/home : 用户目录,存放用户的文件,/lib:存放库文件,后缀为so的文件代表动态链接库。
/lost+found:系统意外终止,存放一些可以找回的文件。
/mnt:挂载外部设备,如挂载光驱:mount –t /dev/cdrom/mnt/cdrom,如
果在双系统中,要查看windows中D盘的文件,首先应该将D盘的文件映射过来,mount –t /dev/hda2/mnt/windows/d
/opt:用户安装的应用程序
/proc:是系统运行的映射,比较重要。里面的文件数字代表进程号。每个进程号目录下包含进程的基本信息。还有其他信息,如cpuinfo等,内核支持的文件系统filesystem等。系统支持的中断interrupts,iomen代表内存分配情况。ioport存放IO端口号。还有分区信息,modole信息,状态信息,版本信息
对于Linux的设备驱动程序,有两种加载模式,一种是直接加载进linux内核,一种是以模块的方式加载到内核。
/sbin: 系统管理的一些工具。如poweroff关机工具。
/usr: 安装系统时很多文件放在此目录下面,包含一些更新等,include包含的头文件,lib 是Linux的库文件,src包含Linux2.4的内核源码
/var:存放是临时变量
3、
第三篇:亲子关系中断[范文]
“亲子关系中断”与疗愈
“亲子关系中断”。通常来说,0-7岁的孩子,尤其是0-3岁之间的孩子,最好和父母在一起,受到父母的照顾。如果要和父母分开的话,分开的时间也不要太长。因为0-3岁的孩子,神经系统还没有足够的承受力,如果跟父母分离很长时间,会产生极度的恐惧,对孩子来讲是一个很大的情绪创伤。孩子长大之后,他/她内心的安全感,他/她与人连结的能力都会受到影响。
“铁脸实验”,把一群一两岁的孩子放在一个游戏室里,让这些孩子去玩,然后让妈妈全部出去。孩子玩了一会,发现妈妈不见了,就开始哭,开始叫。实验人员规定,这种情况下,不管孩子怎么哭怎么叫,妈妈都不要理他/她,妈妈都要拒绝他/她。这样几轮下来之后,突然有一刻,所有的孩子都不再哭了,都安静下来了。这时候妈妈再上来逗孩子,孩子的表情都成了“铁脸”,没表情了,麻木了,不理妈妈了。
实验到了这里,无法在进行下去,因为妈妈们投诉得很厉害。由此也可以看到,当小孩子被妈妈拒绝,被妈妈忽略,被妈妈不理会,离开妈妈的时候,遭到的创伤。
当孩子比较小的时候,你可以上班,可以出差,但是请尽量多的与孩子待在一起。你每次回家,最好多拥抱他/她一会。孩子在父母的怀抱里,感觉是最安全的。父母,尤其是妈妈,既是创伤的开始,也是疗愈的开始。
在孩子0-3岁这段时间,谁在照顾他/她,他/她就可能把这个人当成自己的爸爸妈妈。所以养育孩子,最好父母自己带;第二给自己的父母带,也就是爷爷奶奶、姥姥姥爷带,再其次是给自己的兄弟姐妹带,比如叔叔姑姑;最次是给陌生人带,比如让阿姨带,让保姆带,而且父母也不经常去看孩子,这对孩子会是相当大的心理创伤。
问:如果创伤已经发生,怎样去弥补?
答:刚才说了,有一种方式叫“强抱”,紧紧地去拥抱孩子,不管孩子愿不愿意,你都去拥抱他/她。例如七八岁的孩子,调皮捣蛋,父母去抱他/她,他/她往往会把父母推开。但是你耐心一点,多抱一会儿,比如一个小时,你会发现孩子会软化下来,孩子其实很需要你。
问:如果早年有亲子关系的创伤,父母已经去世了,该怎么办?
答:有个方法,找个老婆回来,先当她是妈,然后再把她当成伴侣,也有疗愈效果。
第四篇:厂用电中断热工总结
厂用电中断热工总结
2014年4月22日变电站#1母线接地导致事故停机,全厂厂用电丢失,导致某些设备在点炉过程中出现一些问题,现将点炉检修过程中出现的问题以及处理方法做以下总结:
1、厂用电丢失会导致热控电源柜及继电器柜断电,在厂用
电正常之检查热控电源柜及热控继电器柜供电电压是否恢复正常,有无断路器或空开跳闸现象。
2、检查火焰电视冷却风压力是不是正常,需不需要退出视
情况而定。
3、现场检修过程中发现罗托克电动门显示屏上显示电量
低的部分电动门出现阀位丢失现象,需要在送电后重新设定阀位。
4、在点炉过程中需要我们强制或者恢复一些信号,我们一
定要在强制信号切除记录登记本上登记并在值长签字以及唐凯的同意下强制或者恢复信号。
5、主控LED屏在断电后组态工程数据丢失,导致LED屏
在送电后无显示,需要我们在日常工作中做数据备份。
6、脱硫电除尘在断电后高、低压侧组态画面无显示,需要
在送电后重新启动组态画面,如无法启动需强制关机启动。
第五篇:场用电中断应急演练总结
场用电中断应急演练总结
一、演练成果
(一)全场员工高度重视,认真组织开展
全场员工对本次事故应急演练,从演练策划、前期准备、组织实施到模拟演练,都认真参与、亲临实战,尤其是刚开始通知过程较为真实。
(二)演练目的明确,预案策划周密
从风场实际出发,确定场用电中断事故的应急演练。
演练检验:
1、应急人员对场用电中断应急预案的熟悉程度。
2、调度系统对接听电话、记录等的规范、时效;
3、风场负责人及相关人员对现场的应急处置能力;
4、应急物资、材料的准备情况。
通过本次演练,对风场备用电源、供电系统的可靠程度进行了论证,并认识到了事故应急设备设施的实际能力。制定出具有实效性的应急处理方案,对厂用电中断应急预案进行完善和补充。提高全场在突发事故发生时,做到人心不慌乱、统一指挥、分级负责、有序进行、安全撤离,实现重大事故伤亡降至最低点。
这次演练贯彻实施了统一领导、综合协调、分级处理的应急处理原则,人员齐全、内容丰富,让参演人员得到了真实的体验,丰富了应急知识,对促进安全应急管理工作具有重要意义。
二、演练存在的不足
(一)现场演练的汇报程序乱,没有达到实战的要求。
(二)在应急人员对场用电中断应急救援预案的熟悉程度方面:
1、部分应急人员对应急救援预案还不熟悉,演练时应用得不太熟悉;
2、责任分工还不太明细。
(三)在调度系统对接听电话、记录等规范、时效方面:
1、调度在启动演练程序出现错误。
2、所有人员在对待演练只是走走过程。
3、记录不规范,没有完整的演练情况记录下来:
4、接听电话也有个别记录错误;
5、现场应急人员对汇报的内容不规范。
(四)本次演练未能对安全工器具进行全面的检验。
(五)本次演练也反应出我场对场用电中断应急演练方面的工作做得还很不完善,在组织协调、演练程序存在较大差距,在突发事故面前,不能够按照调度指挥、分级管理、快速反应、通力协作。
(六)风场检修人员对站内系统不清楚,对场用变切换程序模糊,对开关名称不能对应。
三、以后需做好的工作:
(一)要进一步健全组织指挥体系,理顺各岗位职责,加强统筹领导。
完善应急预案,提高应急处置能力。通过本次演练发现部分员工对应急预案相关内容不熟悉,在演练中紧张、表达不连贯,在以后需加强对应急预案的培训、学习,多搞实战演练,提高员工的应变能力。
加强系统图培训。风场部分新入场员工,对场内一次系统图不够熟悉,对站用变相关开关不熟悉,对基本的倒闸操作程序不熟悉,以后要加强基本知识的培训。增强事故应急处理能力。
加强运行人员事故时调度通话、记录能力。在本次演练中发现运行人员在向调度汇报时紧张,事故说不清楚,思路不清晰、不规范,需加强培训。值班员对事故记录需加强培训,杜绝事故时无记录。