|
与local_irq_disable()和local_irq_enable()不同,disable_irq()、enable_irq()针对的则是外部的中断控制器。在内核中,透过irq_chip结构体来描述中断控制器。该结构体内部封装了中断mask、unmask、ack等成员函数,其定义于include/linux/irq.h:
[cpp] view plain copy
[li]303structirq_chip { [/li][li] [/li][li] 304 const char *name; [/li][li] [/li][li] 305 unsigned int (*irq_startup)(structirq_data *data); [/li][li] [/li][li] 306 void (*irq_shutdown)(struct irq_data *data); [/li][li] [/li][li] 307 void (*irq_enable)(struct irq_data *data); [/li][li] [/li][li] 308 void (*irq_disable)(struct irq_data *data); [/li][li] [/li][li] 309 [/li][li] [/li][li] 310 void (*irq_ack)(struct irq_data *data); [/li][li] [/li][li] 311 void (*irq_mask)(structirq_data *data); [/li][li] [/li][li] 312 void (*irq_mask_ack)(struct irq_data *data); [/li][li] [/li][li] 313 void (*irq_unmask)(struct irq_data *data); [/li][li] [/li][li] 314 void (*irq_eoi)(struct irq_data *data); [/li][li] [/li][li] 315 [/li][li] [/li][li] 316 int (*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest,bool force); [/li][li] [/li][li] 317 int (*irq_retrigger)(struct irq_data *data); [/li][li] [/li][li] 318 int (*irq_set_type)(struct irq_data *data,unsigned int flow_type); [/li][li] [/li][li] 319 int (*irq_set_wake)(struct irq_data *data, unsigned int on); [/li][li] [/li][li] 334}; [/li] 各个芯片公司会将芯片内部的中断控制器实现为irq_chip驱动的形式。受限于中断控制器硬件的能力,这些成员函数并不一定需要全部实现,有时候只需要实现其中的部分函数即可。譬如drivers/pinctrl/pinctrl-sirf.c驱动中的
[cpp] view plain copy
[li]1438staticstruct irq_chip sirfsoc_irq_chip = { [/li][li] [/li][li]1439 .name = "sirf-gpio-irq", [/li][li] [/li][li]1440 .irq_ack = sirfsoc_gpio_irq_ack, [/li][li] [/li][li]1441 .irq_mask = sirfsoc_gpio_irq_mask, [/li][li] [/li][li]1442 .irq_unmask = sirfsoc_gpio_irq_unmask, [/li][li] [/li][li]1443 .irq_set_type = sirfsoc_gpio_irq_type, [/li][li] [/li][li]1444}; [/li] 我们只实现了其中的ack、mask、unmask和set_type成员函数,ack函数用于清中断,mask、unmask用于中断屏蔽和取消中断屏蔽、set_type则用于配置中断的触发方式,如高电平、低电平、上升沿、下降沿等。至于enable_irq()的时候,虽然没有实现irq_enable成员函数,但是内核会间接调用到irq_unmask成员函数,这点从kernel/irq/chip.c可以看出:
[cpp] view plain copy
[li]192voidirq_enable(struct irq_desc *desc) [/li][li] [/li][li] 193{ [/li][li] [/li][li] 194 irq_state_clr_disabled(desc); [/li][li] [/li][li] 195 if (desc->irq_data.chip->irq_enable) [/li][li] [/li][li] 196 desc->irq_data.chip->irq_enable(&desc->irq_data); [/li][li] [/li][li] 197 else [/li][li] [/li][li] 198 desc->irq_data.chip->irq_unmask(&desc->irq_data); [/li][li] [/li][li] 199 irq_state_clr_masked(desc); [/li][li] [/li][li] 200} [/li] 在芯片内部,中断控制器可能不止1个,多个中断控制器之间还很可能是级联的。举个例子,假设芯片内部有一个中断控制器,支持32个中断源,其中有4个来源于GPIO控制器外围的4组GPIO,每组GPIO上又有32个中断(许多芯片的GPIO控制器也同时是一个中断控制器),其关系如下图:
那么,一般来讲,在实际操作中,gpio0_0——gpio0_31这些引脚本身在第1级会使用中断号28,而这些引脚本身的中断号在实现GPIO控制器对应的irq_chip驱动时,我们又会把它映射到Linux系统的32——63号中断。同理,gpio1_0——gpio1_31这些引脚本身在第1级会使用中断号29,而这些引脚本身的中断号在实现GPIO控制器对应的irq_chip驱动时,我们又会把它映射到Linux系统的64——95号中断,以此类推。对于中断号的使用者而言,无需看到这种2级映射关系。如果某设备想申请gpio1_0这个引脚对应的中断,它只需要申请64号中断即可。这个关系图看起来如下:
|
|