中断注册函数 request_irq() 用来注册中断服务。在 2.4 内核中,需要包含的头文件是 #include <linux/sched.h> ,2.6 内核中需要包含的头文件则是#include <linux/interrupt.h> 。函数原型如下:

2.4 内核

 
  
  1. int request_irq (unsigned int irq, void (*handler)(intvoid *, struct pt_regs *), unsigned long frags, const char *device, void *dev_id); 

2.6 内核

 
  
  1. request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev);  

参数说明: 
    在发生对应于第 1个参数 irq 的中断时,则调用第 2 个参数 handler 指定的中断服务函数(也就是把 handler() 中断服务函数注册到内核中 )。 第 3 个参数 flags 指定了快速中断或中断共享等中断处理属性。

    在 2.6 教新的内核里(我的是 2.6.27 ~ 2.6.31 ),在 linux/interrupt.h 中定义操作这个参数的宏如下:

 
  
  1. /*  
  2. * These flags used only by the kernel as part of the  
  3. * irq handling routines.  
  4.  
  5. * IRQF_DISABLED - keep irqs disabled when calling the action handler  
  6. * IRQF_SAMPLE_RANDOM - irq is used to feed the random generator  
  7. * IRQF_SHARED - allow sharing the irq among several devices  
  8. * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur  
  9. * IRQF_TIMER - Flag to mark this interrupt as timer interrupt  
  10. * IRQF_PERCPU - Interrupt is per cpu  
  11. * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing  
  12. * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is  
  13. * registered first in an shared interrupt is considered for  
  14. * performance reasons)  
  15. */  
  16. #define IRQF_DISABLED 0x00000020  
  17. #define IRQF_SAMPLE_RANDOM 0x00000040  
  18. #define IRQF_SHARED 0x00000080  
  19. #define IRQF_PROBE_SHARED 0x00000100  
  20. #define IRQF_TIMER 0x00000200  
  21. #define IRQF_PERCPU 0x00000400  
  22. #define IRQF_NOBALANCING 0x00000800  
  23. #define IRQF_IRQPOLL 0x00001000 

第 4 个参数 name 通常是设备驱动程序的名称。改值用在 /proc/interrupt 系统 (虚拟) 文件上,或内核发生中断错误时使用。 
第 5 个参数 dev_id 可作为共享中断时的中断区别参数,也可以用来指定中断服务函数需要参考的数据地址。 
返回值: 
函数运行正常时返回 0 ,否则返回对应错误的负值。

    对于使用open firmware的系统中,驱动程序在执行ruquest_irq之前要先进行软硬件中断号的映射,具体通过如下函数实现:

 
  
  1. irq_of_parse_and_map(struct device_node * dev, int index); 

    以PowerPC中的mpc83xx_sync.c为例:

 
  
  1. static int sync_ptp_init(void
  2.     int result; 
  3.     struct device_node *np; 
  4.  
  5.     np = of_find_compatible_node(NULL, NULL, "fsl,ucc-ptp"); 
  6.     if (!np) { 
  7.         return -ENODEV; 
  8.     } 
  9.     ptp_virq = irq_of_parse_and_map(np, 1);  /* PTP2 IRQ */ 
  10.     ptp_rtc_virq = irq_of_parse_and_map(np, 2); /* RTC_IRQ */ 
  11.         ... 
  12.     return result; 

通过函数

 
  
  1. struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible); 

根据compatible属性,获得设备结点。遍历Device Tree中所有的设备结点,看看哪个结点的类型、compatible属性与本函数的输入参数匹配,大多数情况下,from、type为NULL。再进行软硬中断号的映射。

 
  
  1. static inline int enable_ptp(int port) 
  2.     ... 
  3.     result = request_irq(ptp_virq, ptp_intr, 
  4.                  0, "ptp", &ptp_reg); 
  5.     if(result < 0) { 
  6.         printk(KERN_ERR "kjb::%s: register irq failed %d\n"
  7.                __FUNCTION__, result); 
  8.     } 
  9.         ... 
  10.     return result; 

完成映射之后进行中断注册,这里以ptp_virq为例。相应的中断处理函数

 
  
  1. static irqreturn_t ptp_intr(int irq, void * _ptp) 
  2.     u32 events; 
  3.  
  4.     KSYNC_DEBUG("ptp intr\n"); 
  5.     events = ptp_reg->ptp_tmr_pevent; 
  6.  
  7.     if (events & PTP_QE_TS_TX_FRAME1) { 
  8.         struct ptp_ts ts; 
  9.         int port = (ucc_port - 1) / 2; 
  10.  
  11.         ts.ts_low = ptp_reg->tmr_ucc_tx_l[port].ts; 
  12.         ts.ts_high = ptp_reg->tmr_ucc_tx_h[port].ts; 
  13.         tx_push_ts(&ts); 
  14.     } 
  15.  
  16.     ptp_reg->ptp_tmr_pevent |= events; 
  17.  
  18.     return IRQ_HANDLED; 

疑问:中断的进入条件是什么?

参考:

http://www.cnblogs.com/alfredzzj/archive/2012/04/03/2431514.html

http://www.linuxidc.com/Linux/2011-08/40710.htm