中断注册函数 request_irq() 用来注册中断服务。在 2.4 内核中,需要包含的头文件是 #include <linux/sched.h> ,2.6 内核中需要包含的头文件则是#include <linux/interrupt.h> 。函数原型如下:
2.4 内核
- int request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long frags, const char *device, void *dev_id);
2.6 内核
- 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 中定义操作这个参数的宏如下:
- /*
- * 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
第 4 个参数 name 通常是设备驱动程序的名称。改值用在 /proc/interrupt 系统 (虚拟) 文件上,或内核发生中断错误时使用。
第 5 个参数 dev_id 可作为共享中断时的中断区别参数,也可以用来指定中断服务函数需要参考的数据地址。
返回值:
函数运行正常时返回 0 ,否则返回对应错误的负值。
对于使用open firmware的系统中,驱动程序在执行ruquest_irq之前要先进行软硬件中断号的映射,具体通过如下函数实现:
- irq_of_parse_and_map(struct device_node * dev, int index);
以PowerPC中的mpc83xx_sync.c为例:
- static int sync_ptp_init(void)
- {
- int result;
- struct device_node *np;
- np = of_find_compatible_node(NULL, NULL, "fsl,ucc-ptp");
- if (!np) {
- return -ENODEV;
- }
- ptp_virq = irq_of_parse_and_map(np, 1); /* PTP2 IRQ */
- ptp_rtc_virq = irq_of_parse_and_map(np, 2); /* RTC_IRQ */
- ...
- return result;
- }
通过函数
- struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible);
根据compatible属性,获得设备结点。遍历Device Tree中所有的设备结点,看看哪个结点的类型、compatible属性与本函数的输入参数匹配,大多数情况下,from、type为NULL。再进行软硬中断号的映射。
- static inline int enable_ptp(int port)
- {
- ...
- result = request_irq(ptp_virq, ptp_intr,
- 0, "ptp", &ptp_reg);
- if(result < 0) {
- printk(KERN_ERR "kjb::%s: register irq failed %d\n",
- __FUNCTION__, result);
- }
- ...
- return result;
- }
完成映射之后进行中断注册,这里以ptp_virq为例。相应的中断处理函数
- static irqreturn_t ptp_intr(int irq, void * _ptp)
- {
- u32 events;
- KSYNC_DEBUG("ptp intr\n");
- events = ptp_reg->ptp_tmr_pevent;
- if (events & PTP_QE_TS_TX_FRAME1) {
- struct ptp_ts ts;
- int port = (ucc_port - 1) / 2;
- ts.ts_low = ptp_reg->tmr_ucc_tx_l[port].ts;
- ts.ts_high = ptp_reg->tmr_ucc_tx_h[port].ts;
- tx_push_ts(&ts);
- }
- ptp_reg->ptp_tmr_pevent |= events;
- return IRQ_HANDLED;
疑问:中断的进入条件是什么?
参考:
http://www.cnblogs.com/alfredzzj/archive/2012/04/03/2431514.html
http://www.linuxidc.com/Linux/2011-08/40710.htm