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 Working\n");
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;
18